From 262b4f0d5ccf50fb6418f212f9b97ec9bf3a7cf7 Mon Sep 17 00:00:00 2001 From: gb <741021719@qq.com> Date: Tue, 2 May 2023 09:50:55 +0800 Subject: [PATCH] synchronize from G200 --- device/gxx-linux/anlogic | Bin 0 -> 84352 bytes device/gxx-linux/applog/applog.cpp | 8 +- device/gxx-linux/capimage/CImageMerge.cpp | 245 ++- device/gxx-linux/capimage/CImageMerge.h | 2 +- device/gxx-linux/capimage/Capturer.cpp | 21 +- device/gxx-linux/capimage/Capturer.h | 2 +- device/gxx-linux/capimage/CorrectParam.cpp | 21 +- device/gxx-linux/capimage/FpgaComm.cpp | 18 +- device/gxx-linux/capimage/FpgaComm.h | 25 +- device/gxx-linux/capimage/GrayLighting.h | 105 ++ device/gxx-linux/capimage/ICapturer.h | 2 + device/gxx-linux/capimage/MonoCapturer.cpp | 301 ++-- device/gxx-linux/capimage/MonoCapturer.h | 4 +- device/gxx-linux/capimage/SysInforTool.cpp | 3 +- device/gxx-linux/capimage/correct_ultis.cpp | 19 +- device/gxx-linux/capimage/correct_ultis.h | 2 - device/gxx-linux/capimage/gvideoisp1.cpp | 1 - device/gxx-linux/capimage/hgutils.cpp | 30 +- device/gxx-linux/capimage/hgutils.h | 3 +- device/gxx-linux/capimage/jsonconfig.cpp | 58 +- device/gxx-linux/capimage/jsonconfig.h | 1 - device/gxx-linux/capimage/scannersysinfo.h | 2 +- device/gxx-linux/capimage/xmake.lua | 2 +- device/gxx-linux/deviceio/DevUtil.h | 3 +- device/gxx-linux/deviceio/Gpio.cpp | 22 +- device/gxx-linux/deviceio/Gpio.h | 2 + device/gxx-linux/deviceio/PinMonitor.cpp | 12 - device/gxx-linux/deviceio/PinMonitor.h | 2 +- device/gxx-linux/deviceio/xmake.lua | 1 - device/gxx-linux/display/DisplayCenter.cpp | 56 + device/gxx-linux/display/DisplayCenter.h | 31 + device/gxx-linux/display/Displaydef.h | 114 ++ device/gxx-linux/display/HgLCDfont.h | 433 +++++ device/gxx-linux/display/LCDDisplay.cpp | 152 ++ device/gxx-linux/display/LCDDisplay.h | 22 + device/gxx-linux/display/Lcd.cpp | 780 +++++++++ device/gxx-linux/display/Lcd.h | 61 + device/gxx-linux/display/xmake.lua | 9 + device/gxx-linux/i2c_key/Makefile | 6 + device/gxx-linux/i2c_key/ch455_key | Bin 0 -> 19520 bytes device/gxx-linux/i2c_key/ch455_key.cpp | 334 ++++ device/gxx-linux/imgproc/CSizedetect.cpp | 5 +- device/gxx-linux/imgproc/CSizedetect.h | 7 +- device/gxx-linux/imgproc/imageencode.cpp | 42 +- device/gxx-linux/imgproc/imageencode.h | 4 + device/gxx-linux/imgproc/xmake.lua | 9 +- device/gxx-linux/keymonitor/keymonitor.cpp | 204 +++ device/gxx-linux/keymonitor/keymonitor.h | 71 + device/gxx-linux/keymonitor/xmake.lua | 9 + device/gxx-linux/mdfusbconfig | Bin 9688 -> 0 bytes device/gxx-linux/motor_run/CuoZhiMotor.cpp | 64 - device/gxx-linux/motor_run/CuoZhiMotor.h | 92 - device/gxx-linux/motor_run/DevUtil.h | 57 - device/gxx-linux/motor_run/Motor.cpp | 69 - device/gxx-linux/motor_run/Motor.h | 72 - device/gxx-linux/motor_run/MotorConfig.h | 367 ---- device/gxx-linux/motor_run/MotorControl.cpp | 60 - device/gxx-linux/motor_run/MotorControl.h | 28 - device/gxx-linux/motor_run/Pwm.cpp | 40 - device/gxx-linux/motor_run/Pwm.h | 22 - device/gxx-linux/motor_run/ZouZhiMotor.cpp | 48 - device/gxx-linux/motor_run/ZouZhiMotor.h | 51 - device/gxx-linux/motor_run/main.cpp | 56 - device/gxx-linux/motor_run/xmake.lua | 89 - device/gxx-linux/motorboard/FeedControl.cpp | 69 + device/gxx-linux/motorboard/FeedControl.h | 31 + device/gxx-linux/motorboard/Imotorboard.cpp | 16 - device/gxx-linux/motorboard/Imotorboard.h | 98 -- device/gxx-linux/motorboard/Jtag.cpp | 95 + device/gxx-linux/motorboard/Jtag.h | 41 + device/gxx-linux/motorboard/Led.cpp | 95 - device/gxx-linux/motorboard/Led.h | 50 - .../{motor_run => motorboard}/MotorConfig.cpp | 38 +- device/gxx-linux/motorboard/MotorConfig.h | 68 + .../gxx-linux/motorboard/MotorSessionInfo.cpp | 117 ++ .../gxx-linux/motorboard/MotorSessionInfo.h | 54 + device/gxx-linux/motorboard/aje2vec.cpp | 918 ++++++++++ device/gxx-linux/motorboard/ajeutil.cpp | 101 ++ device/gxx-linux/motorboard/decodel.cpp | 155 ++ device/gxx-linux/motorboard/jtagupdata.cpp | 26 + device/gxx-linux/motorboard/jtagupdata.h | 22 + device/gxx-linux/motorboard/lzw_lib.cpp | 353 ++++ device/gxx-linux/motorboard/motorboard.cpp | 563 ++++-- device/gxx-linux/motorboard/motorboard.h | 158 +- device/gxx-linux/motorboard/motormanager.cpp | 320 ---- device/gxx-linux/motorboard/motormanager.h | 72 - device/gxx-linux/motorboard/opcode.h | 142 ++ device/gxx-linux/motorboard/sensormonitor.cpp | 127 -- device/gxx-linux/motorboard/sensormonitor.h | 29 - device/gxx-linux/motorboard/vec.cpp | 521 ++++++ device/gxx-linux/motorboard/xmake.lua | 3 +- device/gxx-linux/motorcontroller/IState.h | 32 + device/gxx-linux/motorcontroller/Menu.cpp | 51 + device/gxx-linux/motorcontroller/Menu.h | 16 + .../motorcontroller/MenuComponent.cpp | 135 ++ .../gxx-linux/motorcontroller/MenuComponent.h | 33 + .../gxx-linux/motorcontroller/Menu_Item.cpp | 24 + device/gxx-linux/motorcontroller/Menu_Item.h | 14 + .../motorcontroller/MotorController.cpp | 76 + .../motorcontroller/MotorController.h | 36 + .../motorcontroller/MotorboardParam.cpp | 176 ++ .../motorcontroller/MotorboardParam.h | 39 + device/gxx-linux/motorcontroller/Mt_Count.cpp | 26 + device/gxx-linux/motorcontroller/Mt_Count.h | 12 + device/gxx-linux/motorcontroller/Mt_Error.cpp | 42 + device/gxx-linux/motorcontroller/Mt_Error.h | 12 + device/gxx-linux/motorcontroller/Mt_Idel.cpp | 41 + device/gxx-linux/motorcontroller/Mt_Idel.h | 14 + device/gxx-linux/motorcontroller/Mt_Scan.cpp | 27 + device/gxx-linux/motorcontroller/Mt_Scan.h | 12 + device/gxx-linux/motorcontroller/Mt_Set.cpp | 42 + device/gxx-linux/motorcontroller/Mt_Set.h | 20 + .../gxx-linux/motorcontroller/Mt_Welcome.cpp | 27 + device/gxx-linux/motorcontroller/Mt_Welcome.h | 14 + device/gxx-linux/motorcontroller/Selectable.h | 54 + .../motorcontroller/StateControl.cpp | 404 +++++ .../gxx-linux/motorcontroller/StateControl.h | 61 + .../motorcontroller/StateManager.cpp | 4 + .../gxx-linux/motorcontroller/StateManager.h | 30 + device/gxx-linux/motorcontroller/Statedef.h | 38 + device/gxx-linux/motorcontroller/Subject.h | 17 + device/gxx-linux/motorcontroller/xmake.lua | 10 + device/gxx-linux/out.text | 1 + .../packages/common.pkg/include/StopWatch.h | 47 + .../packages/common.pkg/include/commondef.h | 306 ++-- .../gxx-linux/packages/common.pkg/xmake.lua | 1 - device/gxx-linux/regs/serialib.cpp | 1 + device/gxx-linux/regs/uartregaccessb.cpp | 9 +- device/gxx-linux/scanner/deviceconfig.cpp | 4 + device/gxx-linux/scanner/fsmstate.cpp | 4 +- device/gxx-linux/scanner/fsmstate.h | 6 +- device/gxx-linux/scanner/iimagehandler.h | 75 +- device/gxx-linux/scanner/imagesavehandler.cpp | 2 +- device/gxx-linux/scanner/imagesavehandler.h | 2 +- device/gxx-linux/scanner/imageusbhandler.cpp | 425 ++--- device/gxx-linux/scanner/imageusbhandler.h | 13 +- .../gxx-linux/scanner/imageusbtesthandler.cpp | 2 +- .../gxx-linux/scanner/imageusbtesthandler.h | 2 +- device/gxx-linux/scanner/iscanner.cpp | 344 ---- device/gxx-linux/scanner/iscanner.h | 94 +- device/gxx-linux/scanner/scanner.cpp | 1159 ++++++++++--- device/gxx-linux/scanner/scanner.h | 99 +- device/gxx-linux/scanner/scannero300.cpp | 293 ---- device/gxx-linux/scanner/scannero300.h | 23 - device/gxx-linux/scanner/scannerregs.cpp | 174 +- device/gxx-linux/scanner/scannerregs.h | 2 +- device/gxx-linux/scanner/wakeup.hpp | 3 +- device/gxx-linux/scanner/xmake.lua | 2 +- device/gxx-linux/scannerinfo.json | 20 - device/gxx-linux/scanservice/main.cpp | 317 +--- device/gxx-linux/scanservice/xmake.lua | 3 + device/gxx-linux/service/main.cpp | 2 +- .../small_lcd/app_spi_lcd/.DevUtil.o.d | 170 ++ .../gxx-linux/small_lcd/app_spi_lcd/.Gpio.o.d | 169 ++ .../gxx-linux/small_lcd/app_spi_lcd/.Lcd.o.d | 172 ++ .../gxx-linux/small_lcd/app_spi_lcd/.main.o.d | 172 ++ .../app_spi_lcd}/DevUtil.cpp | 10 +- .../gxx-linux/small_lcd/app_spi_lcd/DevUtil.h | 99 ++ .../gxx-linux/small_lcd/app_spi_lcd/DevUtil.o | Bin 0 -> 30456 bytes .../app_spi_lcd}/Gpio.cpp | 33 +- .../app_spi_lcd}/Gpio.h | 15 +- device/gxx-linux/small_lcd/app_spi_lcd/Gpio.o | Bin 0 -> 41344 bytes .../gxx-linux/small_lcd/app_spi_lcd/Lcd.cpp | 428 +++++ device/gxx-linux/small_lcd/app_spi_lcd/Lcd.h | 73 + device/gxx-linux/small_lcd/app_spi_lcd/Lcd.o | Bin 0 -> 28720 bytes .../gxx-linux/small_lcd/app_spi_lcd/Makefile | 22 + .../small_lcd/app_spi_lcd/Parameters.h | 102 ++ .../small_lcd/app_spi_lcd/filetools.h | 75 + device/gxx-linux/small_lcd/app_spi_lcd/lcd | Bin 0 -> 44464 bytes .../gxx-linux/small_lcd/app_spi_lcd/main.cpp | 35 + device/gxx-linux/small_lcd/app_spi_lcd/main.o | Bin 0 -> 4280 bytes .../gxx-linux/small_lcd/app_spi_lcd/smalllcd | Bin 0 -> 50080 bytes device/gxx-linux/test.cpp | 64 - device/gxx-linux/testcapimage/main.cpp | 302 +++- device/gxx-linux/testdisplay/main.cpp | 18 + device/gxx-linux/testdisplay/xmake.lua | 8 + device/gxx-linux/testimgproc/main.cpp | 155 +- device/gxx-linux/testkeymonitor/main.cpp | 68 + device/gxx-linux/testkeymonitor/xmake.lua | 7 + device/gxx-linux/testlcd/main.cpp | 50 + device/gxx-linux/testlcd/xmake.lua | 7 + device/gxx-linux/testmotorboard/main.cpp | 95 +- device/gxx-linux/testscanner/main.cpp | 35 +- device/gxx-linux/testthread | Bin 0 -> 28672 bytes device/gxx-linux/testusb/main.cpp | 162 +- .../testusb/usb-rk3399/inc/buildconf.h | 12 - .../gxx-linux/testusb/usb-rk3399/inc/camtp.h | 80 - .../testusb/usb-rk3399/inc/default_cfg.h | 57 - .../testusb/usb-rk3399/inc/logs_out.h | 131 -- .../testusb/usb-rk3399/inc/usb_gadget.h | 185 -- .../testusb/usb-rk3399/inc/usbdevice.h | 82 - .../testusb/usb-rk3399/inc/usbstring.h | 42 - device/gxx-linux/testusb/usb-rk3399/inotify.h | 13 - .../gxx-linux/testusb/usb-rk3399/ireceive.h | 17 - .../gxx-linux/testusb/usb-rk3399/itransmit.h | 12 - .../usb-rk3399/src/common/CMakeLists.txt | 17 - .../testusb/usb-rk3399/src/common/cmd.cpp | 106 -- .../testusb/usb-rk3399/src/common/cmd.h | 92 - .../testusb/usb-rk3399/src/common/data.cpp | 466 ----- .../testusb/usb-rk3399/src/common/data.h | 232 --- .../usb-rk3399/src/common/event_monitor.cpp | 257 --- .../usb-rk3399/src/common/event_monitor.h | 153 -- .../usb-rk3399/src/common/ipc_util.cpp | 472 ----- .../testusb/usb-rk3399/src/common/ipc_util.h | 160 -- .../usb-rk3399/src/common/ipc_wrapper.cpp | 373 ---- .../usb-rk3399/src/common/ipc_wrapper.h | 64 - .../usb-rk3399/src/common/json/cJSON.h | 157 -- .../usb-rk3399/src/common/json/json.cpp | 786 --------- .../testusb/usb-rk3399/src/common/json/json.h | 148 -- .../usb-rk3399/src/common/log_util.cpp | 147 -- .../testusb/usb-rk3399/src/common/log_util.h | 64 - .../testusb/usb-rk3399/src/common/packet.h | 315 ---- .../testusb/usb-rk3399/src/common/referer.h | 187 -- .../usb-rk3399/src/common/sys_util.cpp | 854 --------- .../testusb/usb-rk3399/src/common/sys_util.h | 106 -- .../testusb/usb-rk3399/src/common/usb_io.cpp | 790 --------- .../testusb/usb-rk3399/src/common/usb_io.h | 118 -- .../testusb/usb-rk3399/src/logs_out.cpp | 112 -- .../testusb/usb-rk3399/src/usbdevice.cpp | 1530 ----------------- .../testusb/usb-rk3399/src/usbstring.cpp | 349 ---- .../testusb/usb-rk3399/usbimageprocqueue.h | 99 -- .../testusb/usb-rk3399/usbnotify.cpp | 75 - .../gxx-linux/testusb/usb-rk3399/usbnotify.h | 28 - .../testusb/usb-rk3399/usbreceive.cpp | 63 - .../gxx-linux/testusb/usb-rk3399/usbreceive.h | 21 - .../testusb/usb-rk3399/usbservice.cpp | 239 --- .../gxx-linux/testusb/usb-rk3399/usbservice.h | 39 - .../testusb/usb-rk3399/usbtransmit.cpp | 65 - .../testusb/usb-rk3399/usbtransmit.h | 22 - device/gxx-linux/testusb/usb-rk3399/xmake.lua | 11 - device/gxx-linux/testwakeup/main.cpp | 50 + device/gxx-linux/testwakeup/xmake.lua | 8 + device/gxx-linux/tinyfsm-master/COPYING | 21 + device/gxx-linux/tinyfsm-master/ChangeLog | 33 + device/gxx-linux/tinyfsm-master/README.md | 95 + .../tinyfsm-master/doc/10-Introduction.md | 28 + .../tinyfsm-master/doc/20-Installation.md | 68 + .../tinyfsm-master/doc/30-Concepts.md | 38 + .../gxx-linux/tinyfsm-master/doc/40-Usage.md | 238 +++ device/gxx-linux/tinyfsm-master/doc/50-API.md | 206 +++ .../tinyfsm-master/doc/60-Development.md | 26 + .../tinyfsm-master/doc/70-License.md | 9 + .../tinyfsm-master/examples/api/Makefile | 63 + .../examples/api/debugging_switch | Bin 0 -> 16144 bytes .../examples/api/debugging_switch.cpp | 122 ++ .../examples/api/debugging_switch.d | 1 + .../tinyfsm-master/examples/api/mealy_machine | Bin 0 -> 14840 bytes .../examples/api/mealy_machine.cpp | 70 + .../examples/api/mealy_machine.d | 1 + .../tinyfsm-master/examples/api/moore_machine | Bin 0 -> 14968 bytes .../examples/api/moore_machine.cpp | 64 + .../examples/api/moore_machine.d | 1 + .../examples/api/multiple_switch | Bin 0 -> 17568 bytes .../examples/api/multiple_switch.cpp | 145 ++ .../examples/api/multiple_switch.d | 1 + .../examples/api/resetting_switch | Bin 0 -> 15512 bytes .../examples/api/resetting_switch.cpp | 110 ++ .../examples/api/resetting_switch.d | 1 + .../tinyfsm-master/examples/api/simple_switch | Bin 0 -> 14968 bytes .../examples/api/simple_switch.cpp | 85 + .../examples/api/simple_switch.d | 1 + .../tinyfsm-master/examples/elevator/Makefile | 98 ++ .../examples/elevator/README.md | 88 + .../tinyfsm-master/examples/elevator/elevator | Bin 0 -> 17368 bytes .../examples/elevator/elevator.cpp | 115 ++ .../examples/elevator/elevator.d | 2 + .../examples/elevator/elevator.hpp | 55 + .../examples/elevator/elevator.o | Bin 0 -> 13416 bytes .../examples/elevator/fsmlist.hpp | 19 + .../tinyfsm-master/examples/elevator/main.cpp | 40 + .../tinyfsm-master/examples/elevator/main.d | 2 + .../tinyfsm-master/examples/elevator/main.o | Bin 0 -> 4856 bytes .../examples/elevator/motor.cpp | 60 + .../tinyfsm-master/examples/elevator/motor.d | 1 + .../examples/elevator/motor.hpp | 50 + .../tinyfsm-master/examples/elevator/motor.o | Bin 0 -> 8600 bytes .../tinyfsm-master/include/tinyfsm.hpp | 252 +++ device/gxx-linux/tinyfsm-master/library.json | 24 + .../src/app.log => tinyfsm-master/tree.h} | 0 device/gxx-linux/usb/inc/usbdevice.h | 41 +- .../src/{ => async_model}/common/encrypt.cpp | 0 .../src/{ => async_model}/common/encrypt.h | 2 +- .../src/{ => async_model}/common/ipc_util.cpp | 0 .../src/{ => async_model}/common/ipc_util.h | 0 .../src/async_model}/common/json/cJSON.c | 22 +- .../src/{ => async_model}/common/json/cJSON.h | 2 +- .../common/json/gb_json.cpp} | 165 +- .../common/json/gb_json.h} | 58 +- .../src/{ => async_model}/common/log_util.cpp | 12 + .../src/{ => async_model}/common/log_util.h | 1 + .../usb/src/{ => async_model}/common/packet.h | 50 +- .../src/async_model}/common/referer.cpp | 0 .../src/{ => async_model}/common/referer.h | 4 + .../usb/src/async_model/common/sane_cfg.cpp | 911 ++++++++++ .../src/{ => async_model}/common/sane_cfg.h | 78 +- .../src/{ => async_model}/common/sys_util.cpp | 40 + .../src/{ => async_model}/common/sys_util.h | 4 + .../usb/src/async_model/hardware/hardware.cpp | 485 ++++++ .../usb/src/async_model/hardware/hardware.h | 73 + .../async_model/img_process/algs/dogear.cpp | 193 +++ .../src/async_model/img_process/algs/dogear.h | 189 ++ .../img_process/algs/img_algorithm.cpp | 511 ++++++ .../img_process/algs/img_algorithm.h | 180 ++ .../async_model/img_process/cis_preproc.cpp | 316 ++++ .../src/async_model/img_process/cis_preproc.h | 40 + .../async_model/img_process/img_process.cpp | 388 +++++ .../src/async_model/img_process/img_process.h | 74 + .../src/{common => async_model/io}/data.cpp | 2 +- .../usb/src/{common => async_model/io}/data.h | 11 +- .../usb/src/async_model/io/sent_img.cpp | 110 ++ .../usb/src/async_model/io/sent_img.h | 34 + .../src/{common => async_model/io}/usb_io.cpp | 11 +- .../src/{common => async_model/io}/usb_io.h | 8 +- .../src/async_model/scanner/async_scanner.cpp | 841 +++++++++ .../src/async_model/scanner/async_scanner.h | 65 + .../src/async_model/scanner/readonly_opts.cpp | 115 ++ .../src/async_model/scanner/readonly_opts.h | 31 + .../gxx-linux/usb/src/common/CMakeLists.txt | 17 - device/gxx-linux/usb/src/common/cmd.cpp | 106 -- device/gxx-linux/usb/src/common/cmd.h | 92 - .../usb/src/common/event_monitor.cpp | 257 --- .../gxx-linux/usb/src/common/event_monitor.h | 153 -- .../gxx-linux/usb/src/common/ipc_wrapper.cpp | 373 ---- device/gxx-linux/usb/src/common/ipc_wrapper.h | 64 - device/gxx-linux/usb/src/common/json/cJSON.c | 794 --------- device/gxx-linux/usb/src/common/referer.cpp | 202 --- device/gxx-linux/usb/src/common/sane_cfg.cpp | 374 ---- .../gxx-linux/usb/src/hardware/hardware.cpp | 432 ----- device/gxx-linux/usb/src/hardware/hardware.h | 56 - device/gxx-linux/usb/src/usbdevice.cpp | 901 +--------- device/gxx-linux/usb/usbimageprocqueue.h | 87 +- device/gxx-linux/usb/usbnotify.cpp | 3 +- device/gxx-linux/usb/usbreceive.cpp | 3 - device/gxx-linux/usb/usbservice.cpp | 29 +- device/gxx-linux/usb/usbtransmit.cpp | 7 +- device/gxx-linux/usb/vcxprj/usb.vcxproj | 16 +- .../gxx-linux/usb/vcxprj/usb.vcxproj.filters | 48 +- device/gxx-linux/usb/xmake.lua | 7 +- device/gxx-linux/xmake.lua | 9 +- .../sln/usb_tools/Debug/usb_tools.exe | Bin 1746944 -> 1767936 bytes pc/code_twain/sln/usb_tools/DlgScanner.cpp | 70 +- pc/code_twain/sln/usb_tools/DlgScanner.h | 1 + .../sln/usb_tools/scanner/scanner_handler.cpp | 18 +- .../sln/usb_tools/scanner/scanner_handler.h | 2 +- pc/code_twain/sln/usb_tools/usb_tools.vcxproj | 17 +- .../sln/usb_tools/usb_tools.vcxproj.filters | 12 +- pc/code_twain/sln/usb_tools/usb_toolsDlg.cpp | 261 +++ 347 files changed, 19234 insertions(+), 18066 deletions(-) create mode 100644 device/gxx-linux/anlogic create mode 100644 device/gxx-linux/capimage/GrayLighting.h create mode 100644 device/gxx-linux/display/DisplayCenter.cpp create mode 100644 device/gxx-linux/display/DisplayCenter.h create mode 100644 device/gxx-linux/display/Displaydef.h create mode 100644 device/gxx-linux/display/HgLCDfont.h create mode 100644 device/gxx-linux/display/LCDDisplay.cpp create mode 100644 device/gxx-linux/display/LCDDisplay.h create mode 100644 device/gxx-linux/display/Lcd.cpp create mode 100644 device/gxx-linux/display/Lcd.h create mode 100644 device/gxx-linux/display/xmake.lua create mode 100644 device/gxx-linux/i2c_key/Makefile create mode 100644 device/gxx-linux/i2c_key/ch455_key create mode 100644 device/gxx-linux/i2c_key/ch455_key.cpp create mode 100644 device/gxx-linux/keymonitor/keymonitor.cpp create mode 100644 device/gxx-linux/keymonitor/keymonitor.h create mode 100644 device/gxx-linux/keymonitor/xmake.lua delete mode 100644 device/gxx-linux/mdfusbconfig delete mode 100644 device/gxx-linux/motor_run/CuoZhiMotor.cpp delete mode 100644 device/gxx-linux/motor_run/CuoZhiMotor.h delete mode 100644 device/gxx-linux/motor_run/DevUtil.h delete mode 100644 device/gxx-linux/motor_run/Motor.cpp delete mode 100644 device/gxx-linux/motor_run/Motor.h delete mode 100644 device/gxx-linux/motor_run/MotorConfig.h delete mode 100644 device/gxx-linux/motor_run/MotorControl.cpp delete mode 100644 device/gxx-linux/motor_run/MotorControl.h delete mode 100644 device/gxx-linux/motor_run/Pwm.cpp delete mode 100644 device/gxx-linux/motor_run/Pwm.h delete mode 100644 device/gxx-linux/motor_run/ZouZhiMotor.cpp delete mode 100644 device/gxx-linux/motor_run/ZouZhiMotor.h delete mode 100644 device/gxx-linux/motor_run/main.cpp delete mode 100644 device/gxx-linux/motor_run/xmake.lua create mode 100644 device/gxx-linux/motorboard/FeedControl.cpp create mode 100644 device/gxx-linux/motorboard/FeedControl.h delete mode 100644 device/gxx-linux/motorboard/Imotorboard.cpp delete mode 100644 device/gxx-linux/motorboard/Imotorboard.h create mode 100644 device/gxx-linux/motorboard/Jtag.cpp create mode 100644 device/gxx-linux/motorboard/Jtag.h delete mode 100644 device/gxx-linux/motorboard/Led.cpp delete mode 100644 device/gxx-linux/motorboard/Led.h rename device/gxx-linux/{motor_run => motorboard}/MotorConfig.cpp (81%) create mode 100644 device/gxx-linux/motorboard/MotorConfig.h create mode 100644 device/gxx-linux/motorboard/MotorSessionInfo.cpp create mode 100644 device/gxx-linux/motorboard/MotorSessionInfo.h create mode 100644 device/gxx-linux/motorboard/aje2vec.cpp create mode 100644 device/gxx-linux/motorboard/ajeutil.cpp create mode 100644 device/gxx-linux/motorboard/decodel.cpp create mode 100644 device/gxx-linux/motorboard/jtagupdata.cpp create mode 100644 device/gxx-linux/motorboard/jtagupdata.h create mode 100644 device/gxx-linux/motorboard/lzw_lib.cpp delete mode 100644 device/gxx-linux/motorboard/motormanager.cpp delete mode 100644 device/gxx-linux/motorboard/motormanager.h create mode 100644 device/gxx-linux/motorboard/opcode.h delete mode 100644 device/gxx-linux/motorboard/sensormonitor.cpp delete mode 100644 device/gxx-linux/motorboard/sensormonitor.h create mode 100644 device/gxx-linux/motorboard/vec.cpp create mode 100644 device/gxx-linux/motorcontroller/IState.h create mode 100644 device/gxx-linux/motorcontroller/Menu.cpp create mode 100644 device/gxx-linux/motorcontroller/Menu.h create mode 100644 device/gxx-linux/motorcontroller/MenuComponent.cpp create mode 100644 device/gxx-linux/motorcontroller/MenuComponent.h create mode 100644 device/gxx-linux/motorcontroller/Menu_Item.cpp create mode 100644 device/gxx-linux/motorcontroller/Menu_Item.h create mode 100644 device/gxx-linux/motorcontroller/MotorController.cpp create mode 100644 device/gxx-linux/motorcontroller/MotorController.h create mode 100644 device/gxx-linux/motorcontroller/MotorboardParam.cpp create mode 100644 device/gxx-linux/motorcontroller/MotorboardParam.h create mode 100644 device/gxx-linux/motorcontroller/Mt_Count.cpp create mode 100644 device/gxx-linux/motorcontroller/Mt_Count.h create mode 100644 device/gxx-linux/motorcontroller/Mt_Error.cpp create mode 100644 device/gxx-linux/motorcontroller/Mt_Error.h create mode 100644 device/gxx-linux/motorcontroller/Mt_Idel.cpp create mode 100644 device/gxx-linux/motorcontroller/Mt_Idel.h create mode 100644 device/gxx-linux/motorcontroller/Mt_Scan.cpp create mode 100644 device/gxx-linux/motorcontroller/Mt_Scan.h create mode 100644 device/gxx-linux/motorcontroller/Mt_Set.cpp create mode 100644 device/gxx-linux/motorcontroller/Mt_Set.h create mode 100644 device/gxx-linux/motorcontroller/Mt_Welcome.cpp create mode 100644 device/gxx-linux/motorcontroller/Mt_Welcome.h create mode 100644 device/gxx-linux/motorcontroller/Selectable.h create mode 100644 device/gxx-linux/motorcontroller/StateControl.cpp create mode 100644 device/gxx-linux/motorcontroller/StateControl.h create mode 100644 device/gxx-linux/motorcontroller/StateManager.cpp create mode 100644 device/gxx-linux/motorcontroller/StateManager.h create mode 100644 device/gxx-linux/motorcontroller/Statedef.h create mode 100644 device/gxx-linux/motorcontroller/Subject.h create mode 100644 device/gxx-linux/motorcontroller/xmake.lua create mode 100644 device/gxx-linux/out.text delete mode 100644 device/gxx-linux/scanner/iscanner.cpp delete mode 100644 device/gxx-linux/scanner/scannero300.cpp delete mode 100644 device/gxx-linux/scanner/scannero300.h delete mode 100644 device/gxx-linux/scannerinfo.json create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/.DevUtil.o.d create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/.Gpio.o.d create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/.Lcd.o.d create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/.main.o.d rename device/gxx-linux/{motor_run => small_lcd/app_spi_lcd}/DevUtil.cpp (79%) create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.h create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.o rename device/gxx-linux/{motor_run => small_lcd/app_spi_lcd}/Gpio.cpp (68%) rename device/gxx-linux/{motor_run => small_lcd/app_spi_lcd}/Gpio.h (84%) create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/Gpio.o create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/Lcd.cpp create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/Lcd.h create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/Lcd.o create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/Makefile create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/Parameters.h create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/filetools.h create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/lcd create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/main.cpp create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/main.o create mode 100644 device/gxx-linux/small_lcd/app_spi_lcd/smalllcd delete mode 100644 device/gxx-linux/test.cpp create mode 100644 device/gxx-linux/testdisplay/main.cpp create mode 100644 device/gxx-linux/testdisplay/xmake.lua create mode 100644 device/gxx-linux/testkeymonitor/main.cpp create mode 100644 device/gxx-linux/testkeymonitor/xmake.lua create mode 100644 device/gxx-linux/testlcd/main.cpp create mode 100644 device/gxx-linux/testlcd/xmake.lua create mode 100644 device/gxx-linux/testthread delete mode 100644 device/gxx-linux/testusb/usb-rk3399/inc/buildconf.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/inc/camtp.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/inc/default_cfg.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/inc/logs_out.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/inc/usb_gadget.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/inc/usbdevice.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/inc/usbstring.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/inotify.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/ireceive.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/itransmit.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/CMakeLists.txt delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/cmd.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/cmd.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/data.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/data.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/event_monitor.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/event_monitor.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/ipc_util.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/ipc_util.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/ipc_wrapper.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/ipc_wrapper.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/json/cJSON.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/json/json.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/json/json.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/log_util.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/log_util.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/packet.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/referer.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/sys_util.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/sys_util.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/usb_io.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/common/usb_io.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/logs_out.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/usbdevice.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/src/usbstring.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/usbimageprocqueue.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/usbnotify.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/usbnotify.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/usbreceive.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/usbreceive.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/usbservice.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/usbservice.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/usbtransmit.cpp delete mode 100644 device/gxx-linux/testusb/usb-rk3399/usbtransmit.h delete mode 100644 device/gxx-linux/testusb/usb-rk3399/xmake.lua create mode 100644 device/gxx-linux/testwakeup/main.cpp create mode 100644 device/gxx-linux/testwakeup/xmake.lua create mode 100644 device/gxx-linux/tinyfsm-master/COPYING create mode 100644 device/gxx-linux/tinyfsm-master/ChangeLog create mode 100644 device/gxx-linux/tinyfsm-master/README.md create mode 100644 device/gxx-linux/tinyfsm-master/doc/10-Introduction.md create mode 100644 device/gxx-linux/tinyfsm-master/doc/20-Installation.md create mode 100644 device/gxx-linux/tinyfsm-master/doc/30-Concepts.md create mode 100644 device/gxx-linux/tinyfsm-master/doc/40-Usage.md create mode 100644 device/gxx-linux/tinyfsm-master/doc/50-API.md create mode 100644 device/gxx-linux/tinyfsm-master/doc/60-Development.md create mode 100644 device/gxx-linux/tinyfsm-master/doc/70-License.md create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/Makefile create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/debugging_switch create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/debugging_switch.cpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/debugging_switch.d create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/mealy_machine create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/mealy_machine.cpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/mealy_machine.d create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/moore_machine create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/moore_machine.cpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/moore_machine.d create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/multiple_switch create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/multiple_switch.cpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/multiple_switch.d create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/resetting_switch create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/resetting_switch.cpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/resetting_switch.d create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/simple_switch create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/simple_switch.cpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/api/simple_switch.d create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/Makefile create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/README.md create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/elevator create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/elevator.cpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/elevator.d create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/elevator.hpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/elevator.o create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/fsmlist.hpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/main.cpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/main.d create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/main.o create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/motor.cpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/motor.d create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/motor.hpp create mode 100644 device/gxx-linux/tinyfsm-master/examples/elevator/motor.o create mode 100644 device/gxx-linux/tinyfsm-master/include/tinyfsm.hpp create mode 100644 device/gxx-linux/tinyfsm-master/library.json rename device/gxx-linux/{testusb/usb-rk3399/src/app.log => tinyfsm-master/tree.h} (100%) rename device/gxx-linux/usb/src/{ => async_model}/common/encrypt.cpp (100%) rename device/gxx-linux/usb/src/{ => async_model}/common/encrypt.h (98%) rename device/gxx-linux/usb/src/{ => async_model}/common/ipc_util.cpp (100%) rename device/gxx-linux/usb/src/{ => async_model}/common/ipc_util.h (100%) rename device/gxx-linux/{testusb/usb-rk3399/src => usb/src/async_model}/common/json/cJSON.c (97%) rename device/gxx-linux/usb/src/{ => async_model}/common/json/cJSON.h (99%) rename device/gxx-linux/usb/src/{common/json/json.cpp => async_model/common/json/gb_json.cpp} (72%) rename device/gxx-linux/usb/src/{common/json/json.h => async_model/common/json/gb_json.h} (66%) rename device/gxx-linux/usb/src/{ => async_model}/common/log_util.cpp (91%) rename device/gxx-linux/usb/src/{ => async_model}/common/log_util.h (90%) rename device/gxx-linux/usb/src/{ => async_model}/common/packet.h (93%) rename device/gxx-linux/{testusb/usb-rk3399/src => usb/src/async_model}/common/referer.cpp (100%) rename device/gxx-linux/usb/src/{ => async_model}/common/referer.h (98%) create mode 100644 device/gxx-linux/usb/src/async_model/common/sane_cfg.cpp rename device/gxx-linux/usb/src/{ => async_model}/common/sane_cfg.h (52%) rename device/gxx-linux/usb/src/{ => async_model}/common/sys_util.cpp (96%) rename device/gxx-linux/usb/src/{ => async_model}/common/sys_util.h (97%) create mode 100644 device/gxx-linux/usb/src/async_model/hardware/hardware.cpp create mode 100644 device/gxx-linux/usb/src/async_model/hardware/hardware.h create mode 100644 device/gxx-linux/usb/src/async_model/img_process/algs/dogear.cpp create mode 100644 device/gxx-linux/usb/src/async_model/img_process/algs/dogear.h create mode 100644 device/gxx-linux/usb/src/async_model/img_process/algs/img_algorithm.cpp create mode 100644 device/gxx-linux/usb/src/async_model/img_process/algs/img_algorithm.h create mode 100644 device/gxx-linux/usb/src/async_model/img_process/cis_preproc.cpp create mode 100644 device/gxx-linux/usb/src/async_model/img_process/cis_preproc.h create mode 100644 device/gxx-linux/usb/src/async_model/img_process/img_process.cpp create mode 100644 device/gxx-linux/usb/src/async_model/img_process/img_process.h rename device/gxx-linux/usb/src/{common => async_model/io}/data.cpp (99%) rename device/gxx-linux/usb/src/{common => async_model/io}/data.h (94%) create mode 100644 device/gxx-linux/usb/src/async_model/io/sent_img.cpp create mode 100644 device/gxx-linux/usb/src/async_model/io/sent_img.h rename device/gxx-linux/usb/src/{common => async_model/io}/usb_io.cpp (98%) rename device/gxx-linux/usb/src/{common => async_model/io}/usb_io.h (97%) create mode 100644 device/gxx-linux/usb/src/async_model/scanner/async_scanner.cpp create mode 100644 device/gxx-linux/usb/src/async_model/scanner/async_scanner.h create mode 100644 device/gxx-linux/usb/src/async_model/scanner/readonly_opts.cpp create mode 100644 device/gxx-linux/usb/src/async_model/scanner/readonly_opts.h delete mode 100644 device/gxx-linux/usb/src/common/CMakeLists.txt delete mode 100644 device/gxx-linux/usb/src/common/cmd.cpp delete mode 100644 device/gxx-linux/usb/src/common/cmd.h delete mode 100644 device/gxx-linux/usb/src/common/event_monitor.cpp delete mode 100644 device/gxx-linux/usb/src/common/event_monitor.h delete mode 100644 device/gxx-linux/usb/src/common/ipc_wrapper.cpp delete mode 100644 device/gxx-linux/usb/src/common/ipc_wrapper.h delete mode 100644 device/gxx-linux/usb/src/common/json/cJSON.c delete mode 100644 device/gxx-linux/usb/src/common/referer.cpp delete mode 100644 device/gxx-linux/usb/src/common/sane_cfg.cpp delete mode 100644 device/gxx-linux/usb/src/hardware/hardware.cpp delete mode 100644 device/gxx-linux/usb/src/hardware/hardware.h diff --git a/device/gxx-linux/anlogic b/device/gxx-linux/anlogic new file mode 100644 index 0000000000000000000000000000000000000000..35790d2cae6297fcb129a2112852a9c2fa95bbce GIT binary patch literal 84352 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 literal 0 HcmV?d00001 diff --git a/device/gxx-linux/applog/applog.cpp b/device/gxx-linux/applog/applog.cpp index 08fa38e..1f625df 100644 --- a/device/gxx-linux/applog/applog.cpp +++ b/device/gxx-linux/applog/applog.cpp @@ -1,8 +1,8 @@ #include "applog.h" -#include -#include -#include -#include +#include "spdlog/spdlog.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include "spdlog/sinks/basic_file_sink.h" +#include "spdlog/sinks/rotating_file_sink.h" #include "stringex.hpp" #include #include diff --git a/device/gxx-linux/capimage/CImageMerge.cpp b/device/gxx-linux/capimage/CImageMerge.cpp index a7d5f53..667baf0 100644 --- a/device/gxx-linux/capimage/CImageMerge.cpp +++ b/device/gxx-linux/capimage/CImageMerge.cpp @@ -8,68 +8,195 @@ CImageMerge::~CImageMerge() } cv::Mat CImageMerge::MergeImage(cv::Mat &srcMat, int dstwidth, int dstheight) { - cv::Mat retMat(dstheight, dstwidth, CV_8UC3); + cv::Mat retMat(dstheight, dstwidth, CV_8UC3); - if (!srcMat.empty()) - { - std::vector ch_mats; - int blockcnt = 12; - int spitWidth = srcMat.cols / blockcnt; + if (!srcMat.empty()) + { + std::vector ch_mats; + int blockcnt = 12; + int spitWidth = srcMat.cols / blockcnt; - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 3; j++) - { - std::cout << " index " << (i * 3 + j) << " x " << spitWidth * (i * 3 + j) << " y " << 0 << " width " << spitWidth << " height " << dstheight << std::endl; - ch_mats.push_back(srcMat(cv::Rect(spitWidth * (i * 3 + j), 0, spitWidth, dstheight))); - } - cv::merge(ch_mats, retMat(cv::Rect(spitWidth * i, 0, spitWidth, dstheight))); - ch_mats.clear(); - } - return retMat; - } + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 3; j++) + { + std::cout << " index " << (i * 3 + j) << " x " << spitWidth * (i * 3 + j) << " y " << 0 << " width " << spitWidth << " height " << dstheight << std::endl; + ch_mats.push_back(srcMat(cv::Rect(spitWidth * (i * 3 + j), 0, spitWidth, dstheight))); + } + cv::merge(ch_mats, retMat(cv::Rect(spitWidth * i, 0, spitWidth, dstheight))); + ch_mats.clear(); + } + return retMat; + } } -cv::Mat CImageMerge::MergeImage(bool iscolor, cv::Mat &srcMat, int dstwidth, int dstheight,std::uint32_t fpga_vs) +cv::Mat CImageMerge::MergeImage(bool iscolor, cv::Mat &srcMat, int dstwidth, int dstheight, unsigned int fgpaversion) { - int blockcnt = 12; - int spitWidth = srcMat.cols / blockcnt; - int abortwidth; // = spitWidth == 3888 ? 432 : (spitWidth == 2592 ? 216 : 144); - if (!iscolor) //灰度 - { - abortwidth = spitWidth == 1296 ? 432 : (spitWidth == 648 ? 216 : 144); - } - else - { - abortwidth = spitWidth == 3888 ? 432 : (spitWidth == 1944 ? 216 : 144); - } + if (fgpaversion == 0x00090002) + { + int blockcnt = iscolor ? 18 : 6; + int spitWidth = srcMat.cols / blockcnt / 2; //一面的灰度图像宽度 + int abortwidth = spitWidth == 1296 ? 432 : (spitWidth == 648 ? 216 : 144); - cv::Mat dst(dstheight, dstwidth - abortwidth * 2, CV_8UC(iscolor ? 3 : 1)); - if (!iscolor) - { - for (int i = 0; i < 2; i++) - { - srcMat(cv::Rect((dstwidth / 2 + abortwidth) * i, 0, dstwidth / 2 - abortwidth, dstheight)).copyTo(dst(cv::Rect(dst.cols / 2 * i, 0, dst.cols / 2, dstheight))); - } - srcMat.release(); - } - else - { - std::vector m_splits; - std::vector m_index = {0, 3, 8, 11, 2, 5, 6, 9, 1, 4, 7, 10}; - for (int i = 0; i < 3; i++) - { - int startindex = i == 0 ? 0 : (i == 1 ? 4 : 8); - cv::Mat t_mat(dstheight, dstwidth - abortwidth * 2, CV_8UC1); - srcMat(cv::Rect(spitWidth * m_index[startindex + 0], 0, spitWidth, dstheight)).copyTo(t_mat(cv::Rect(0, 0, spitWidth, dstheight))); - srcMat(cv::Rect(spitWidth * m_index[startindex + 1], 0, spitWidth - abortwidth, dstheight)).copyTo(t_mat(cv::Rect(spitWidth, 0, spitWidth - abortwidth, dstheight))); - srcMat(cv::Rect(spitWidth * m_index[startindex + 2] + abortwidth, 0, spitWidth - abortwidth, dstheight)).copyTo(t_mat(cv::Rect(spitWidth * 2 - abortwidth, 0, spitWidth - abortwidth, dstheight))); - srcMat(cv::Rect(spitWidth * m_index[startindex + 3], 0, spitWidth, dstheight)).copyTo(t_mat(cv::Rect(spitWidth * 3 - abortwidth * 2, 0, spitWidth, dstheight))); - m_splits.push_back(t_mat); - } - cv::merge(m_splits, dst); - m_splits.clear(); - } - srcMat.release(); - return dst; -} \ No newline at end of file + std::cout << "image is color " << iscolor << std::endl; + cv::Mat dst(dstheight, dstwidth - 2 * abortwidth, CV_8UC(iscolor ? 3 : 1)); + if (!iscolor) + { + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 6; j++) + { + int index = i == 0 ? 5 : 11; + int bandindex = (i * 6 + j); + if (bandindex == 0 || bandindex == 11) + { + if (bandindex == 0) + srcMat(cv::Rect(bandindex * spitWidth, 0, spitWidth - abortwidth, srcMat.rows)).copyTo(dst(cv::Rect(spitWidth * (index - j), 0, spitWidth - abortwidth, srcMat.rows))); + else + srcMat(cv::Rect(bandindex * spitWidth + abortwidth, 0, spitWidth - abortwidth, srcMat.rows)).copyTo(dst(cv::Rect(spitWidth * (index - j) - abortwidth, 0, spitWidth - abortwidth, srcMat.rows))); + } + else + { + if (bandindex >= 6) + srcMat(cv::Rect(bandindex * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(dst(cv::Rect(spitWidth * (index - j) - 2 * abortwidth, 0, spitWidth, srcMat.rows))); + else + srcMat(cv::Rect(bandindex * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(dst(cv::Rect(spitWidth * (index - j), 0, spitWidth, srcMat.rows))); + } + } + } + srcMat.release(); + } + else + { + std::vector m_splits = { + cv::Mat(dstheight, dstwidth - 2 * abortwidth, CV_8UC1), + cv::Mat(dstheight, dstwidth - 2 * abortwidth, CV_8UC1), + cv::Mat(dstheight, dstwidth - 2 * abortwidth, CV_8UC1)}; + int item_index[3][4] = { + {11, 2, 35, 26}, // R + {17, 8, 29, 20}, // B + {14, 5, 32, 23} // G + }; + + for (size_t j = 0; j < 3; j++) + { + // Front + srcMat(cv::Rect((item_index[j][0] - 0) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 0, 0, spitWidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][0] - 1) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 1, 0, spitWidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][0] - 2) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 2, 0, spitWidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][1] - 0) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 3, 0, spitWidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][1] - 1) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 4, 0, spitWidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][1] - 2) * spitWidth, 0, spitWidth - abortwidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 5, 0, spitWidth - abortwidth, srcMat.rows))); + // Back + srcMat(cv::Rect((item_index[j][2] - 0) * spitWidth + abortwidth, 0, spitWidth - abortwidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 6 - abortwidth, 0, spitWidth - abortwidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][2] - 1) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 7 - 2 * abortwidth, 0, spitWidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][2] - 2) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 8 - 2 * abortwidth, 0, spitWidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][3] - 0) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 9 - 2 * abortwidth, 0, spitWidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][3] - 1) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 10 - 2 * abortwidth, 0, spitWidth, srcMat.rows))); + srcMat(cv::Rect((item_index[j][3] - 2) * spitWidth, 0, spitWidth, srcMat.rows)).copyTo(m_splits[j](cv::Rect(spitWidth * 11 - 2 * abortwidth, 0, spitWidth, srcMat.rows))); + } + cv::merge(m_splits, dst); + m_splits.clear(); + } + srcMat.release(); + // static int index=0; + // cv::imwrite(std::to_string(++index)+".bmp",dst); + return dst; + } + else if(fgpaversion == 0x00090001) + { + int blockcnt = 12; + int spitWidth = srcMat.cols / blockcnt; + int abortwidth; // = spitWidth == 3888 ? 432 : (spitWidth == 2592 ? 216 : 144); + if (!iscolor) //灰度 + { + abortwidth = spitWidth == 1296 ? 432 : (spitWidth == 648 ? 216 : 144); + } + else + { + abortwidth = spitWidth == 3888 ? 432 : (spitWidth == 1944 ? 216 : 144); + } + + cv::Mat dst(dstheight, dstwidth - abortwidth * 2, CV_8UC(iscolor ? 3 : 1)); + if (!iscolor) + { + for (int i = 0; i < 2; i++) + { + srcMat(cv::Rect((dstwidth / 2 + abortwidth) * i, 0, dstwidth / 2 - abortwidth, dstheight)).copyTo(dst(cv::Rect(dst.cols / 2 * i, 0, dst.cols / 2, dstheight))); + } + srcMat.release(); + } + else + { + std::vector m_splits; + std::vector m_index = {0, 3, 8, 11, 2, 5, 6, 9, 1, 4, 7, 10}; + for (int i = 0; i < 3; i++) + { + int startindex = i == 0 ? 0 : (i == 1 ? 4 : 8); + cv::Mat t_mat(dstheight, dstwidth - abortwidth * 2, CV_8UC1); + srcMat(cv::Rect(spitWidth * m_index[startindex + 0], 0, spitWidth, dstheight)).copyTo(t_mat(cv::Rect(0, 0, spitWidth, dstheight))); + srcMat(cv::Rect(spitWidth * m_index[startindex + 1], 0, spitWidth - abortwidth, dstheight)).copyTo(t_mat(cv::Rect(spitWidth, 0, spitWidth - abortwidth, dstheight))); + srcMat(cv::Rect(spitWidth * m_index[startindex + 2] + abortwidth, 0, spitWidth - abortwidth, dstheight)).copyTo(t_mat(cv::Rect(spitWidth * 2 - abortwidth, 0, spitWidth - abortwidth, dstheight))); + srcMat(cv::Rect(spitWidth * m_index[startindex + 3], 0, spitWidth, dstheight)).copyTo(t_mat(cv::Rect(spitWidth * 3 - abortwidth * 2, 0, spitWidth, dstheight))); + m_splits.push_back(t_mat); + } + cv::merge(m_splits, dst); + m_splits.clear(); + } + srcMat.release(); + return dst; + } + else if(fgpaversion == 0x0009000a) + { + auto switchblock = [](std::vector> v,cv::Mat& src,cv::Mat& dst,int block_width,int block_height,int abortwidth){ + int copyindex =0; + for(int i=0;i> v {{3,0},{5,1},{4,2},{1,3},{0,4},{2,5},{10,6},{9,7},{11,8},{6,9},{8,10},{7,11}}; + if(!iscolor) + { + int abortwidth = srcMat.cols /12 == 1296 ? 432 :( srcMat.cols /12== 648 ? 216 :144); + cv::Mat dst(srcMat.rows, srcMat.cols - abortwidth*2, CV_8UC1); + switchblock(v,srcMat,dst,srcMat.cols /12,srcMat.rows,abortwidth); + return dst; + } + else + { + cv::Mat retMat(srcMat.rows, srcMat.cols / 3, CV_8UC3); + int spitWidth = srcMat.cols / 12 ; + for(int i=0;i<4;i++) + { + // 1 2 0 + std::vector ch_mats; + if(i < 2){ + ch_mats.push_back(srcMat(cv::Rect(spitWidth * (i * 3 + 0), 0, spitWidth, srcMat.rows))); + ch_mats.push_back(srcMat(cv::Rect(spitWidth * (i * 3 + 2), 0, spitWidth, srcMat.rows))); + ch_mats.push_back(srcMat(cv::Rect(spitWidth * (i * 3 + 1), 0, spitWidth, srcMat.rows))); + } + else + { + ch_mats.push_back(srcMat(cv::Rect(spitWidth * (i * 3 + 2), 0, spitWidth, srcMat.rows))); + ch_mats.push_back(srcMat(cv::Rect(spitWidth * (i * 3 + 0), 0, spitWidth, srcMat.rows))); + ch_mats.push_back(srcMat(cv::Rect(spitWidth * (i * 3 + 1), 0, spitWidth, srcMat.rows))); + } + cv::merge(ch_mats, retMat(cv::Rect(spitWidth * i, 0, spitWidth, srcMat.rows))); + ch_mats.clear(); + } + int abortwidth = retMat.cols /12 == 1296 ? 432 :(retMat.cols /12 == 648 ? 216 :144); + cv::Mat dst(retMat.rows, retMat.cols - abortwidth*2, CV_8UC3); + switchblock(v,retMat,dst,retMat.cols /12,retMat.rows,abortwidth); + printf(" dst.cols = %d dst.rows = %d dst.channels = %d \n",dst.cols,dst.rows,dst.channels()); + return dst; + } + } + return srcMat; +} diff --git a/device/gxx-linux/capimage/CImageMerge.h b/device/gxx-linux/capimage/CImageMerge.h index e93214e..a4e1374 100644 --- a/device/gxx-linux/capimage/CImageMerge.h +++ b/device/gxx-linux/capimage/CImageMerge.h @@ -10,5 +10,5 @@ public: ~CImageMerge(); public: cv::Mat MergeImage(cv::Mat& srcMat,int dstwidth,int dstheight); - cv::Mat MergeImage(bool iscolor,cv::Mat& srcMat,int dstwidth,int dstheight,std::uint32_t fpga_vs); + cv::Mat MergeImage(bool iscolor,cv::Mat& srcMat,int dstwidth,int dstheight,unsigned int fgpaversion=0x00090001); }; diff --git a/device/gxx-linux/capimage/Capturer.cpp b/device/gxx-linux/capimage/Capturer.cpp index 0fa1f3a..4494a7d 100644 --- a/device/gxx-linux/capimage/Capturer.cpp +++ b/device/gxx-linux/capimage/Capturer.cpp @@ -12,7 +12,6 @@ #include "applog.h" #include "stringex.hpp" #include -#include #include "filetools.h" #include "CameraParam.h" #include "correct_ultis.h" @@ -29,9 +28,12 @@ cv::Mat mBuffMat; cv::Mat out; Capturer::Capturer() - : reset_pin(new GpioOut(Fpga_Reset)), - initDone_pin(new Gpio(71)), - fpgaLoad(new GpioOut(70)), + : vdd_cis_3voff_pin(new GpioOut(CIS_3v3_Off)), + vdd_vis_5ven_pin(new GpioOut(CIS_5v_En)), + reset_pin(new GpioOut(Fpga_Reset)), + image_in_transfer_pin(new Gpio(Image_In_Transfer)), + initDone_pin(new Gpio(Fpga_InitDone)), + fpgaLoad(new GpioOut(Fpga_Load)), bcorrecting(false) { LOG_INIT(); @@ -47,6 +49,9 @@ Capturer::~Capturer() { } +void Capturer::Fpga_regsAccess_reset(bool enable){ + +} void Capturer::open() { cisconfigs = getcisparams(); @@ -97,7 +102,8 @@ void Capturer::open(HGScanConfig config,FPGAConfigParam fpgaparam) if (exp_ratio > 2.0) exp_ratio = 0.1; cisconfigs = getcisparams(); - int height = 1632; + auto hgsize = papersMap[(PaperSize)config.g200params.paper]; + int height = hgsize.height; fpgaComm->setColorMode(config.g200params.color ? 1 : 0); auto info = jsonconfig().getscannerinfo(); //set_sp(config.g200params.color ? cisconfigs.color.sp : cisconfigs.gray.sp); //0x03fa : 0x0bf0 @@ -300,12 +306,11 @@ void Capturer::configFPGAParam(bool iscorrect, int mode) // val+=step; // exp_ratio += 0.1; - // printf("\n\n\n----------------\n"); // for (int i = 0; i < 2; i++) // { // for (int j = 0; j < 6; j++) // { - // offsets[i][j]=j==4?200:0; + // printf("gains[%d][%d] = %d \r\n", i, j, gains[i][j]); // printf("offsets[%d][%d] = %d \r\n", i, j, offsets[i][j]); // if (j < 3) @@ -348,6 +353,8 @@ void Capturer::setFGPAParmas(int exposures[2][3], int gains[2][6], int offsets[2 void *Capturer::readFrame(int timeout) { auto ret= video->read_frame(timeout); + unsigned int val; + //fpgaComm->update(); return ret; } diff --git a/device/gxx-linux/capimage/Capturer.h b/device/gxx-linux/capimage/Capturer.h index 3df8c93..ee8fd5f 100644 --- a/device/gxx-linux/capimage/Capturer.h +++ b/device/gxx-linux/capimage/Capturer.h @@ -11,7 +11,7 @@ class Capturer : public ICapturer public: Capturer(); virtual ~Capturer(); - + virtual void Fpga_regsAccess_reset(bool enable); virtual void open(); virtual void open(HGScanConfig config,FPGAConfigParam fpgaparam); virtual void close(); diff --git a/device/gxx-linux/capimage/CorrectParam.cpp b/device/gxx-linux/capimage/CorrectParam.cpp index bc51dc6..513e2dd 100644 --- a/device/gxx-linux/capimage/CorrectParam.cpp +++ b/device/gxx-linux/capimage/CorrectParam.cpp @@ -54,6 +54,7 @@ std::vector CorrectParam::GetCorrectParams() std::ifstream i(JSONPATH); json j; i >> j; + i.close(); std::vector vct_param; for (json::iterator it = j.begin(); it != j.end(); ++it) { @@ -114,6 +115,7 @@ void CorrectParam::SaveCorrectParam(FPGAConfigParam& parms) } ofstream ofs(JSONPATH); ofs << std::setw(4) << j << std::endl; + ofs.close(); } void CorrectParam::initdefaultpapram() @@ -129,11 +131,7 @@ void CorrectParam::initdefaultpapram() //彩色 300 dpi param.ColorMode = 1;//彩色 param.DpiMode = 2;//300 dpi -#ifdef G200 - param.MaxBright = 190; -#else param.MaxBright = 200; -#endif param.MaxExp = 1100; param.HRatio = 1065353216; param.VRatio = 1065353216; @@ -155,7 +153,7 @@ void CorrectParam::initdefaultpapram() //灰度 300 dpi param.ColorMode = 0;//灰度 - param.MaxBright = 200; + param.MaxBright = 220; param.LutPath = LUT300GRAYPATH; param.TextLutPath = TEXTLUT300GRAYPATH; param.Flat_BwPath = LUT300_GRAY_BLACKPATH; @@ -164,11 +162,7 @@ void CorrectParam::initdefaultpapram() js.push_back(t_j); //彩色 200 dpi -#ifdef G200 - param.MaxBright = 190; -#else param.MaxBright = 200; -#endif param.ColorMode = 1;//彩色 param.DpiMode = 1;//200 dpi param.LutPath = LUT200COLORPATH; @@ -186,7 +180,7 @@ void CorrectParam::initdefaultpapram() js.push_back(t_j); //灰度 200dpi - param.MaxBright = 200; + param.MaxBright = 220; param.ColorMode = 0;//灰度 param.LutPath = LUT200GRAYPATH; param.TextLutPath = TEXTLUT200GRAYPATH; @@ -196,11 +190,7 @@ void CorrectParam::initdefaultpapram() js.push_back(t_j); //彩色 600 dpi -#ifdef G200 - param.MaxBright = 190; -#else param.MaxBright = 200; -#endif param.ColorMode = 1;//彩色 param.DpiMode = 0x03;//200 dpi param.LutPath = LUT600COLORPATH; @@ -220,7 +210,7 @@ void CorrectParam::initdefaultpapram() //灰度 600dpi - param.MaxBright = 200; + param.MaxBright = 220; param.ColorMode = 0;//灰度 param.LutPath = LUT600GRAYPATH; param.TextLutPath = TEXTLUT600GRAYPATH; @@ -231,6 +221,7 @@ void CorrectParam::initdefaultpapram() std::ofstream ofs(JSONPATH); ofs << std::setw(4) << js << std::endl; + ofs.close(); } } } diff --git a/device/gxx-linux/capimage/FpgaComm.cpp b/device/gxx-linux/capimage/FpgaComm.cpp index 0c88f22..626336d 100644 --- a/device/gxx-linux/capimage/FpgaComm.cpp +++ b/device/gxx-linux/capimage/FpgaComm.cpp @@ -17,7 +17,7 @@ FpgaComm::FpgaComm() { - m_regsAccess.reset(new UartRegsAccess(MOTOR_UART, 921600, 0x03, 0x83)); + m_regsAccess.reset(new UartRegsAccess(FPGA_UART, 921600, 0x03, 0x83)); update(0); Reg(AledR).sample = 256; @@ -29,7 +29,7 @@ void FpgaComm::regsAccess_reset(bool enable){ if(enable) { if(!m_regsAccess.get()) - m_regsAccess.reset(new UartRegsAccess(MOTOR_UART, 921600, 0x03, 0x83)); + m_regsAccess.reset(new UartRegsAccess(FPGA_UART, 921600, 0x03, 0x83)); update(0); return; } @@ -38,11 +38,15 @@ void FpgaComm::regsAccess_reset(bool enable){ } bool FpgaComm::read(unsigned int addr, unsigned int& val) { - return m_regsAccess->read(addr, val); + if(m_regsAccess.get()) + return m_regsAccess->read(addr, val); + return false; } bool FpgaComm::write(unsigned int addr, unsigned int val) { - return m_regsAccess->write(addr, val); + if(m_regsAccess.get()) + return m_regsAccess->write(addr, val); + return false; } void FpgaComm::setFrameHeight(int height){ @@ -377,14 +381,10 @@ void FpgaComm::setEnTestBit(bool en) void FpgaComm::setVsp(unsigned int Aside,unsigned int BSide) { - unsigned int regv; CISVSP vsp; - read(13,regv); - vsp.value = regv; vsp.bits.ASide_VSP = Aside; vsp.bits.BSide_VSP = BSide; vsp.bits.reserved=0; printf("setVsp A side =%d B side=%d vspint=%08x \n", vsp.bits.ASide_VSP, vsp.bits.BSide_VSP,vsp.value); - write(13,vsp.value); - WR_Reg(AledR); + m_regsAccess->write(13,vsp.value); } \ No newline at end of file diff --git a/device/gxx-linux/capimage/FpgaComm.h b/device/gxx-linux/capimage/FpgaComm.h index 9e5df19..71c7c02 100644 --- a/device/gxx-linux/capimage/FpgaComm.h +++ b/device/gxx-linux/capimage/FpgaComm.h @@ -93,7 +93,16 @@ typedef struct CIS_LED_UV unsigned short int ledBSide; } CisLedUv; - +typedef union CIS_VSP +{ + struct + { + unsigned int ASide_VSP:8; + unsigned int BSide_VSP:8; + unsigned int reserved : 16; + } bits; + int value; +} CISVSP; typedef union Fpga_Params { @@ -122,17 +131,6 @@ typedef union Fpga_Params } FpgaParams; -typedef union CIS_VSP -{ - struct - { - unsigned int ASide_VSP:8; - unsigned int BSide_VSP:8; - unsigned int reserved : 16; - } bits; - int value; -} CISVSP; - class FpgaComm : public IRegsAccess { public: @@ -189,10 +187,9 @@ public: void update(int times); void enableJamCheck(bool b); void resetADC(); - void setVsp(unsigned int Aside,unsigned int BSide); virtual bool write(unsigned int addr, unsigned int val); virtual bool read(unsigned int addr, unsigned int& val); - + void setVsp(unsigned int Aside,unsigned int BSide); private: FpgaParams fpgaParams; std::shared_ptr m_regsAccess; diff --git a/device/gxx-linux/capimage/GrayLighting.h b/device/gxx-linux/capimage/GrayLighting.h new file mode 100644 index 0000000..8108274 --- /dev/null +++ b/device/gxx-linux/capimage/GrayLighting.h @@ -0,0 +1,105 @@ +#pragma once +#include +#include +#include + +std::vector caculate_abcd(std::vector> point) +{ + int MaxElement = point.size() - 1; + //计算常数f + double f = point[0].second; + //求解 + int n, m; + + std::vector> a; + + for (int i = 0; i < MaxElement; i++) + { + std::vector b; + b.resize(MaxElement + 1); + a.push_back(b); + } + + for (int i = 0; i < MaxElement; i++) + { + for (int j = 0; j < MaxElement; j++) + a[i][j] = pow(point[i + 1].first, MaxElement - j); + a[i][MaxElement] = point[i + 1].second - f; + } + + int i, j; + n = MaxElement; + + for (j = 0; j < n; j++) + { + double max = 0; + double imax = 0; + for (i = j; i < n; i++) + { + if (imax < fabs(a[i][j])) { + imax = fabs(a[i][j]); + max = a[i][j];//得到各行中所在列最大元素 + m = i; + } + } + if (fabs(a[j][j]) != max) + { + double b = 0; + for (int k = j; k < n + 1; k++) { + b = a[j][k]; + a[j][k] = a[m][k]; + a[m][k] = b; + } + } + + for (int r = j; r < n + 1; r++) + { + a[j][r] = a[j][r] / max;//让该行的所在列除以所在列的第一个元素,目的是让首元素为1 + } + + for (i = j + 1; i < n; i++) + { + double c = a[i][j]; + if (c == 0.0) continue; + for (int s = j; s < n + 1; s++) { + a[i][s] = a[i][s] - a[j][s] * c;//前后行数相减,使下一行或者上一行的首元素为0 + } + } + } + for (i = n - 2; i >= 0; i--) + { + for (j = i + 1; j < n; j++) + { + a[i][n] = a[i][n] - a[j][n] * a[i][j]; + } + } + + std::vector result; + for (int k = 0; k < n; k++) + result.push_back(a[k][n]); + result.push_back(f); + return result; +} + +double caculate_value(const std::vector& abcd, double x) +{ + return abcd[0] * x * x * x + abcd[1] * x * x + abcd[2] * x + abcd[3]; +} + +void brightness(cv::Mat& lut, int alpha = 170) +{ + std::vector> pos; + pos.push_back(std::pair(0, 0)); + pos.push_back(std::pair(64, 64)); + pos.push_back(std::pair(alpha, 255)); + pos.push_back(std::pair(255, 255)); + std::vector abcd = caculate_abcd(pos); + + uchar table[256]; + for (int i = 0; i < 256; i++) + table[i] = static_cast(caculate_value(abcd, i)); + + uchar* ptr = lut.data; + for (int i = 0, length = lut.total() * lut.channels(); i < length; i++) + ptr[i] = table[ptr[i]]; +} \ No newline at end of file diff --git a/device/gxx-linux/capimage/ICapturer.h b/device/gxx-linux/capimage/ICapturer.h index dbb3c5e..955bbc8 100644 --- a/device/gxx-linux/capimage/ICapturer.h +++ b/device/gxx-linux/capimage/ICapturer.h @@ -7,10 +7,12 @@ #include "commondef.h" #include "CorrectParam.h" + class ICapturer { public: virtual ~ICapturer() {} + virtual void Fpga_regsAccess_reset(bool enable) = 0; virtual void open() = 0; virtual void open(HGScanConfig config,FPGAConfigParam fpgaparam) = 0; virtual void close() = 0; diff --git a/device/gxx-linux/capimage/MonoCapturer.cpp b/device/gxx-linux/capimage/MonoCapturer.cpp index d1bd23d..b794ad3 100644 --- a/device/gxx-linux/capimage/MonoCapturer.cpp +++ b/device/gxx-linux/capimage/MonoCapturer.cpp @@ -10,9 +10,6 @@ #include "stringex.hpp" #include "filetools.h" #include "CImageMerge.h" -#include "commondef.h" -#include "hgutils.h" -#include "dailex.hpp" #include "jsonconfig.h" #include "ThreadPool.h" @@ -52,7 +49,8 @@ MonoCapturer::MonoCapturer() : vdd_cis_3voff_pin(new GpioOut(CIS_3v3_Off)), fpgaLoad(new Gpio(70)), fpga_conf_done(new Gpio(69)),//gpio init 导出 scanservice 仅操作IO fpga_conf_initn(new Gpio(71)),//gpio init 导出 scanservice 仅操作IO - bcorrecting(false) + bcorrecting(false), + m_fpgaversion(0x00090001) { LOG_INIT(); fpga_conf_done->setDirection(Gpio::in); @@ -62,7 +60,7 @@ MonoCapturer::MonoCapturer() : vdd_cis_3voff_pin(new GpioOut(CIS_3v3_Off)), fpgaComm->setDelayTime(0X3e8); // fpgaComm->update(); video.reset(new VIDEO_CLASS()); - // GetFpgaparam(0x01,0); + fpgaComm->read(15,m_fpgaversion); } MonoCapturer::~MonoCapturer() @@ -77,12 +75,16 @@ void MonoCapturer::open() { } +void MonoCapturer::Fpga_regsAccess_reset(bool enable){ + if(fpgaComm.get()) + fpgaComm->regsAccess_reset(enable); + fpgaComm->update(0); +} + void MonoCapturer::open(HGScanConfig config,FPGAConfigParam fpgaparam) { + fpgaComm->update(1); - // reset_pin->setValue(Gpio::Low); - // std::this_thread::sleep_for(std::chrono::milliseconds(50)); - // reset_pin->setValue(Gpio::High); bool dunnancis = true; int dpi; if (dunnancis) @@ -95,6 +97,7 @@ void MonoCapturer::open(HGScanConfig config,FPGAConfigParam fpgaparam) int channels = mode == 0x01 ? 3 : 1; int width = channelwidth * channels; auto phyHeight = paperHeight[(PaperSize)config.g200params.paper]; + printf("\n ########## phyHeight = %d ",phyHeight); int pixheight; // = ((int)((phyHeight / 25.4 * (dpi == 0x02 ? 300 : (dpi == 0x03 ? 600 : 200)) + 2) / 3)) * 3 * 2; if (dunnancis) { @@ -111,39 +114,18 @@ void MonoCapturer::open(HGScanConfig config,FPGAConfigParam fpgaparam) int dstheight = pixheight; int fpgaheight = mode == 0x1 ? dstheight / 2 * 3 : dstheight / 2; //彩色配置fpga 高度要为目标图像高度的3倍 - //FPGAConfigParam fpgaparam = GetFpgaparam(config.g200params.dpi, mode);// == 0x02 ? 2 : (config.g200params.dpi == 0x03 ? 3 : 2) + //fpgaparam = GetFpgaparam(config.g200params.dpi, mode);// == 0x02 ? 2 : (config.g200params.dpi == 0x03 ? 3 : 2) // FPGAConfigParam fpgaparam = GetFpgaparam(dpi, mode); printf("dpi = %d fpgaparam.sp=%d exp=%d gain=%d offset=%d LUT=%s \n", dpi, fpgaparam.Sp, fpgaparam.ExposureB[0], fpgaparam.GainB[0], fpgaparam.OffsetB[0], fpgaparam.LutPath.c_str()); // int startsample= cistype.GetCisType()==CISVendor::DUNNAN_CIS_V0?205:262; -#ifdef G300 - int startsample = 202; - dpi = 0; - width = 1728; - if (papersMap.count((PaperSize)config.g200params.paper) > 0) - { - dstheight = papersMap[(PaperSize)config.g200params.paper].height; - } - else - { - dstheight = papersMap[PaperSize::G400_A4].height; //不区分G300 G400 - } - dstheight = config.g200params.color ? dstheight : dstheight /3; - if(config.g200params.dpi != 1) - dstheight = std::min(16002,dstheight*3/2); - fpgaheight = dstheight; -#else - int startsample = 208; - std::uint32_t m_fpgaversion = 0; - fpgaComm->read(15,m_fpgaversion); - if(Dail().GetValue().dails.in_voltage3 == 0) - startsample = 262; + int startsample = 205; + uint tmp_vs = 0; + fpgaComm->read(15,tmp_vs); + if(tmp_vs >= 0x90002) + startsample = 205; else - startsample = m_fpgaversion == 0x90002? 205 : 208; -#endif + startsample = 208; - float v_ratio = *((float*)(&fpgaparam.VRatio)); - fpgaparam.Sp /= v_ratio; - printf("\n apply sp = %d, v_ratio =%f",fpgaparam.Sp,v_ratio); ModeFpga fpgamod = { .colorMode = mode, .dpi = dpi, @@ -155,15 +137,14 @@ void MonoCapturer::open(HGScanConfig config,FPGAConfigParam fpgaparam) .sp = fpgaparam.Sp}; // 600DPI 0x1450 300DPI 0xe10 fpgaComm->setRegs(0x01, *((int *)(&fpgamod))); fpgaComm->setSample(startsample); + if(tmp_vs != 0x9000a) + fpgaComm->setVsp(2,2); + else{ + fpgaComm->setVsp(80,120); + } fpgaComm->enableLed(true); fpgaComm->setEnTestCol(false); fpgaComm->setEnTestBit(false); - auto vsp_value = jsonconfig().getscannerinfo(); - if(vsp_value.clr_maxbright > 20 || vsp_value.clr_maxbright < 1) - vsp_value.clr_maxbright = 2; - if(vsp_value.gray_maxbright > 20 || vsp_value.gray_maxbright < 1) - vsp_value.gray_maxbright = 2; - fpgaComm->setVsp(vsp_value.clr_maxbright,vsp_value.gray_maxbright); // fpgaComm->update(2); configFPGAParam(mode, config.g200params.dpi); // fpgaComm->update(3); @@ -195,11 +176,6 @@ void MonoCapturer::close() //fpga_reload(); } -void MonoCapturer::Fpga_regsAccess_reset(bool enable){ - if(fpgaComm.get()) - fpgaComm->regsAccess_reset(enable); -} - void MonoCapturer::start() { if (video.get()) @@ -232,32 +208,25 @@ int MonoCapturer::getautosizeheight() unsigned int reg8 = 0; fpgaComm->read(8, reg8); - // std::cout << "1 reg[8]:" << string_format("0x%08x", reg8) << std::endl; - // fpgaComm->update(4); + fpgaComm->read(14, val); int regv = val; val &= 0x0000ffff; - // std::cout << string_format("ONE height = %d reg[14] = %d \n", val, regv); - // fpgaComm->update(5); + fpgaComm->write(8, reg8 & 0xfffffff7); - // std::cout << string_format("ONE reg[8] = %d \n", reg8 & 0xfffffff7); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); - // fpgaComm->update(6); + fpgaComm->read(14, val); regv = val; val &= 0x0000ffff; fpgaComm->read(8, reg8); - // std::cout << "2 reg[8]:" << string_format("0x%08x", reg8) << std::endl; + std::cout << string_format("TWO height = %d reg[14] = %d \n", val, regv); std::this_thread::sleep_for(std::chrono::milliseconds(5)); fpgaComm->write(8, reg8 | 0x8); - // fpgaComm->write(8,0x02260008); - // fpgaComm->update(7); - // fpgaComm->read(8, reg8); - // std::cout << "2 reg[8]:" << string_format("0x%08x", reg8) << std::endl; - return val; - // return fpgaComm->getFrameHeight(); + return val; } void MonoCapturer::set_size(int width, int height) { @@ -343,15 +312,11 @@ void MonoCapturer::reset() int MonoCapturer::width() { -#ifdef G300 - return 1728; -#else int dpi = fpgaComm->getDpi(); int channel = 1; int width = dpi == 0x02 ? 1296 * channel : (dpi == 0x03 ? (2592 * channel) : (864 * channel)); // printf("get width = %d \n", width); return width; -#endif } int MonoCapturer::height() @@ -366,14 +331,15 @@ int MonoCapturer::color() void MonoCapturer::init_autocorrect(int colormode) { - std::thread t_correctthread = std::thread(&MonoCapturer::correctcolor, this); + std::thread t_correctthread = std::thread(&MonoCapturer::correctcolor, this,colormode); t_correctthread.detach(); } void MonoCapturer::configFPGAParam(int mode, int dpi) { printf("dpi = %d mode = %d \n", dpi, mode); - //fpgaComm->resetADC(); + + fpgaComm->resetADC(); FPGAConfigParam fpgaparam = GetFpgaparam(dpi, mode); // int offF[6]={0,0,0,0,0,200}; // int offB[6]={0,0,0,0,0,0}; @@ -390,7 +356,7 @@ void MonoCapturer::configFPGAParam(int mode, int dpi) printf("fpgaparam.ExposureB[%d] = %d \n", i, fpgaparam.ExposureB[i % 3]); } - std::this_thread::sleep_for(std::chrono::milliseconds(3)); + std::this_thread::sleep_for(std::chrono::milliseconds(2)); fpgaComm->setAOffset(i, fpgaparam.OffsetF[i]); // fpgaComm->setAOffset(i,offF[i]); printf("fpgaparam.setAOffset[%d] = %d \n", i, fpgaparam.OffsetF[i]); @@ -413,6 +379,7 @@ void MonoCapturer::openDevice(int dpi, int mode) // reset_pin->setValue(Gpio::Low); // std::this_thread::sleep_for(std::chrono::milliseconds(50)); // reset_pin->setValue(Gpio::High); + fpgaComm->read(15,m_fpgaversion); int config_dpi = dpi == 1 ? 2 : dpi; int channelwidth = config_dpi == 0x02 ? 1296 : (config_dpi == 0x03 ? 2592 : 864); int channels = mode == 0x01 ? 3 : 1; @@ -421,26 +388,15 @@ void MonoCapturer::openDevice(int dpi, int mode) int fpgaheight = mode == 0x1 ? dstheight / 2 * 3 : dstheight; //彩色配置fpga 高度要为目标图像高度的3倍 FPGAConfigParam fpgaparam = GetFpgaparam(dpi, mode); -#ifdef G300 - int startsample = 202; - config_dpi = 0; - width = 1728; - dstheight = mode ? 6000 : 2000; - fpgaheight = dstheight; -#else - int startsample = 208; - std::uint32_t m_fpgaversion = 0; - fpgaComm->read(15,m_fpgaversion); - if(Dail().GetValue().dails.in_voltage3 == 0) - startsample = 262; - else - startsample = m_fpgaversion == 0x90002? 205 : 208; -#endif printf("fpgaparam.sp=%d exp=%d gain=%d offset=%d LUT=%s", fpgaparam.Sp, fpgaparam.ExposureB[0], fpgaparam.GainB[0], fpgaparam.OffsetB[0], fpgaparam.LutPath.c_str()); // int startsample= cistype.GetCisType()==CISVendor::DUNNAN_CIS_V0?205:262; - float v_ratio = *((float*)(&fpgaparam.VRatio)); - fpgaparam.Sp *= v_ratio; - printf("\n openDevice apply sp = %d, v_ratio =%f",fpgaparam.Sp,v_ratio); + int startsample = 205; + uint tmp_vs = 0; + fpgaComm->read(15,tmp_vs); + if(tmp_vs >= 0x90002) + startsample = 205; + else + startsample = 208; ModeFpga fpgamod = { .colorMode = mode, .dpi = config_dpi, @@ -455,12 +411,24 @@ void MonoCapturer::openDevice(int dpi, int mode) fpgaComm->enableLed(true); fpgaComm->setEnTestCol(false); fpgaComm->setEnTestBit(false); - auto vsp_value = jsonconfig().getscannerinfo(); - if(vsp_value.clr_maxbright > 20 || vsp_value.clr_maxbright < 1) - vsp_value.clr_maxbright = 2; - if(vsp_value.gray_maxbright > 20 || vsp_value.gray_maxbright < 1) - vsp_value.gray_maxbright = 2; - fpgaComm->setVsp(vsp_value.clr_maxbright,vsp_value.gray_maxbright); + if(tmp_vs != 0x9000a) + fpgaComm->setVsp(2,2); + else + { + // ifstream iF("/home/vspF"); + // ifstream iB("/home/vspB"); + // int vspF,vspB; + // iF >> vspF; + // iB >> vspB; + // if(vspF ==0 || vspB == 0) + // { + // vspF = 75; + // vspB = 85; + // } + // printf("!!!!!!!!!!! vspF=%d vspB = %d \n",vspF,vspB); + // fpgaComm->setVsp(vspF,vspB); + fpgaComm->setVsp(80,120); + } configFPGAParam(mode, dpi); video->open(width, dstheight); // 300dpi 7344/2 600dpi 7344 @@ -478,12 +446,11 @@ void MonoCapturer::openDevice(int dpi, int mode) void MonoCapturer::creatcorrectconfig(int dpi, int mode) { - printf(" opendevice"); openDevice(dpi, mode); - printf(" opendevice end "); bool isDone = false; int i = 1; initStep1(); + while (!isDone) //先暗场 { string log = "==============================第" + to_string(i) + "次==============================="; @@ -513,6 +480,7 @@ void MonoCapturer::creatcorrectconfig(int dpi, int mode) i++; } printf("creatcorrectconfig %s \n", (mode == IMAGE_COLOR ? " Color" : " Gray")); + //creatLUTData(dpi, mode); video->close(); } @@ -521,20 +489,12 @@ static int savelutindex = 0; bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) { int config_dpi = dpi == 1 ? 2 : dpi; -#ifdef G300 int offset_indexs[] = {3, 4, 5, 2, 1, 0, 0, 1, 2, 5, 4, 3}; -#else - int offset_indexs[] = {0, 1, 2, 5, 4, 3, 3, 4, 5, 2, 1, 0}; -#endif int channels = mode == IMAGE_COLOR ? 3 : 1; int height = 100; int width = config_dpi == 0x02 ? 1296 : (config_dpi == 0x03 ? 2592 : 864); int orgimgwidth = width * 2 * 3 * channels; int dstwidth = width * 2 * 3; -#ifdef G300 - orgimgwidth = 1728 * channels * 3; - height = 6000 / 9 *3 ; -#endif bool isNeedSave = true; string log; void *data = video->read_frame(10000); @@ -548,14 +508,11 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) return isNeedSave; } cv::Mat src(height, orgimgwidth, CV_8UC1, data); - //cv::imwrite(std::to_string(savelutindex++) + ".jpg", src); -#ifdef G300 - cv::Mat mrgmat = GetStitchMat(mode ==1?1:0,orgimgwidth,height,src); -#else + // cv::imwrite(std::to_string(savelutindex++) + ".jpg", src); CImageMerge t_marge; - cv::Mat mrgmat = t_marge.MergeImage(mode == 0x01, src, dstwidth, height,0x90001); -#endif + cv::Mat mrgmat = t_marge.MergeImage(mode == 0x01, src, dstwidth, height,m_fpgaversion); mrgmat = mrgmat(cv::Rect(0,20,mrgmat.cols,mrgmat.rows-20)); + // cv::imwrite(std::to_string(savelutindex++) + "mrg.jpg", mrgmat); // return false; FPGAConfigParam param = GetFpgaparam(dpi, mode); @@ -563,11 +520,11 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) { double offValues[12]; std::vector bflags; - for (volatile int n = 0; n < 2; n++) + for (int n = 0; n < 2; n++) { cv::Mat img = mrgmat(cv::Rect(mrgmat.cols * n / 2, 10, mrgmat.cols / 2, mrgmat.rows - 10)).clone(); int offset_total = 0; - for (volatile int s = 0; s < 6; s++) // + for (int s = 0; s < 6; s++) // { int k = n * 6 + s; int offset_wdth; @@ -579,9 +536,7 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) { offset_wdth = config_dpi == 0x03 ? 1296 : (config_dpi == 0x02 ? 648 : 432); } -#ifdef G300 - offset_wdth =432; -#endif + double min,max; //auto t_mat= img(cv::Rect(offset_total, 10, offset_wdth, img.rows - 10)); //cv::minMaxLoc(t_mat,&min,&max); @@ -589,7 +544,6 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) //printf("AAAAAAAAAAAAAAAAAAAAAAAAAAA min = %.2f max= %.2f mean = %0.2f \n",min,max); offset_total += offset_wdth; offValues[k] = mean.val[0]; - printf("\noffValues[%d] = %f",k,mean.val[0]); bflags.push_back(false); //offValues[k] = min; } @@ -597,7 +551,7 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) // std::string clrmode = (mode == 0x01 ? "彩色" : " 灰度"); // log = "开始" + clrmode + "暗场校正 \n"; - for (volatile int s = 0; s < 2; s++) + for (int s = 0; s < 2; s++) { int offsets[6]; // = (int *)(s == 0 ? ¶m.OffsetF[0] : ¶m.OffsetB[0]); memcpy(offsets, (s == 0 ? ¶m.OffsetF[0] : ¶m.OffsetB[0]), sizeof(param.OffsetF)); @@ -696,6 +650,7 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) log = "开始彩色明场校正 \r\n"; if (m_captureCallback) m_captureCallback(mode, log); + double coefficient[3] ={ 1.2,0.6,1.2}; for (int s = 0; s < 2; s++) { int exposures[3]; // = (int *)(s == 0 ? param.ExposureF : param.ExposureB); @@ -704,12 +659,14 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) { int k = (3 * s + x); int diff = LIGHT_DIFF(param.MaxBright, *((double *)values + k)); + //int diff = LIGHT_DIFF(param.MaxBright,((values[s][0]*coefficient[0]+values[s][1]*coefficient[1]+values[s][2]*coefficient[2])/3.0)); log += " 明场:" + std::to_string(k) + ";diff:" + std::to_string(diff) + "\r\n"; if(abs(diff) > 30) radio = 2; else radio = 1; double step = diff * radio; + //double step = diff / coefficient[x]; int preStep = *((int *)expStep + k); if (step * preStep < 0) { @@ -752,6 +709,7 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) if (m_captureCallback) m_captureCallback(mode, log); // log =""; + //imwrite("/home/linaro/"+to_string(dpi)+"color.jpg", mrgmat); imwrite(param.Flat_WhitePath, mrgmat); } } @@ -804,7 +762,8 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) if (exp >(param.Sp -5)) exp = (param.Sp -5); - float coffe[3] = {1, 1, 1}; // 0.2, 1,0.51 + //float coffe[3] = {0.8, 1, 1}; // 0.2, 1,0.51 + float coffe[3] = {1,1,1}; for (int k = 0; k < 3; k++) { *(exposures + k) = (int)(exp * coffe[k]); @@ -836,60 +795,88 @@ bool MonoCapturer::saveLutImg(int dpi, int mode, bool black) return isNeedSave; } -void MonoCapturer::correctcolor() +void MonoCapturer::correctcolor(int correctmode) { - printf(" correctcolor start \n"); auto _start = std::chrono::steady_clock::now(); ThreadPool pool(2); std::queue> fu_correct; std::string loginfo = "Start Correctcolor 200DPI COLOR \r\n"; - // if (m_captureCallback) - // m_captureCallback(0x01, loginfo); - creatcorrectconfig(0x01, IMAGE_COLOR); - auto param = GetFpgaparam(0x01,IMAGE_COLOR); - fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x01,IMAGE_COLOR,param);})); - loginfo = "-----------200DPI COLOR Correct Done----------- \r\n\r\n Start Correctcolor 200DPI GRAY \r\n"; - if (m_captureCallback) - m_captureCallback(0x01, loginfo); - creatcorrectconfig(0x01, IMAGE_GRAY); - param = GetFpgaparam(0x01,IMAGE_GRAY); - fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x01,IMAGE_GRAY,param);})); - loginfo = "-----------200DPI Gray Correct Done----------- \r\n\r\n Start Correctcolor 200DPI COLOR \r\n"; - if (m_captureCallback) - m_captureCallback(0x02, loginfo); - - creatcorrectconfig(0x02, IMAGE_COLOR); - param = GetFpgaparam(0x02,IMAGE_COLOR); - fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x02,IMAGE_COLOR,param);})); - loginfo = "-----------300DPI COLOR Correct Done----------- \r\n\r\n Start Correctcolor 300DPI GRAY \r\n"; - if (m_captureCallback) - m_captureCallback(0x02, loginfo); - creatcorrectconfig(0x02, IMAGE_GRAY); - param = GetFpgaparam(0x02,IMAGE_GRAY); - fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x02,IMAGE_GRAY,param);})); - loginfo = "-----------300DPI Gray Correct Done----------- \r\n\r\n Start Correctcolor 600DPI COLOR \r\n"; -#ifndef G300 + if((correctmode == 0) || (correctmode == 2)){ + if (m_captureCallback) + m_captureCallback(0x01, loginfo); + creatcorrectconfig(0x01, IMAGE_COLOR); + auto param = GetFpgaparam(0x01,IMAGE_COLOR); + fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x01,IMAGE_COLOR,param);})); + loginfo = "-----------200DPI COLOR Correct Done----------- \r\n\r\n "; + if (m_captureCallback) + m_captureCallback(0x01, loginfo); + } + if((correctmode == 0) || (correctmode == 1)){ + loginfo = "Start Correctcolor 200DPI GRAY \r\n"; + if (m_captureCallback) + m_captureCallback(0x01, loginfo); + creatcorrectconfig(0x01, IMAGE_GRAY); + auto param = GetFpgaparam(0x01,IMAGE_GRAY); + fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x01,IMAGE_GRAY,param);})); + loginfo = "-----------200DPI Gray Correct Done----------- \r\n\r\n "; + if (m_captureCallback) + m_captureCallback(0x02, loginfo); + } + if((correctmode == 0) || (correctmode == 4)){ + loginfo = "Start Correctcolor 300DPI COLOR \r\n"; + if (m_captureCallback) + m_captureCallback(0x01, loginfo); + creatcorrectconfig(0x02, IMAGE_COLOR); + auto param = GetFpgaparam(0x02,IMAGE_COLOR); + fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x02,IMAGE_COLOR,param);})); + loginfo = "-----------300DPI COLOR Correct Done----------- \r\n\r\n "; + if (m_captureCallback) + m_captureCallback(0x02, loginfo); + } + if((correctmode == 0) || (correctmode == 3)){ + loginfo = "Start Correctcolor 300DPI GRAY \r\n"; + if (m_captureCallback) + m_captureCallback(0x01, loginfo); + creatcorrectconfig(0x02, IMAGE_GRAY); + auto param = GetFpgaparam(0x02,IMAGE_GRAY); + fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x02,IMAGE_GRAY,param);})); + loginfo = "-----------300DPI Gray Correct Done----------- \r\n\r\n "; + if (m_captureCallback) + m_captureCallback(0x03, loginfo); + } + if((correctmode == 0) || (correctmode == 6)){ + loginfo = "Start Correctcolor 600DPI COLOR \r\n"; + if (m_captureCallback) + m_captureCallback(0x01, loginfo); + creatcorrectconfig(0x03, IMAGE_COLOR); + auto param = GetFpgaparam(0x03,IMAGE_COLOR); + fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x03,IMAGE_COLOR,param);})); + loginfo = "-----------600DPI COLOR Correct Done----------- \r\n\r\n "; + if (m_captureCallback) + m_captureCallback(0x03, loginfo); + } + if((correctmode == 0) || (correctmode == 5)){ + loginfo = "Start Correctcolor 600DPI GRAY \r\n"; + if (m_captureCallback) + m_captureCallback(0x01, loginfo); + creatcorrectconfig(0x03, IMAGE_GRAY); + auto param = GetFpgaparam(0x03,IMAGE_GRAY); + fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x03,IMAGE_GRAY,param);})); + loginfo = "-----------600DPI Gray Correct Done----------- \r\n\r\n "; + if (m_captureCallback) + m_captureCallback(0x03, loginfo); + } + if((correctmode < 0) || (correctmode > 6)){ + loginfo = "不支持的校正模式...\r\n"; if (m_captureCallback) m_captureCallback(0x03, loginfo); - creatcorrectconfig(0x03, IMAGE_COLOR); - param = GetFpgaparam(0x03,IMAGE_COLOR); - fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x03,IMAGE_COLOR,param);})); - loginfo = "-----------600DPI COLOR Correct Done----------- \r\n\r\n Start Correctcolor 600DPI GRAY \r\n"; - if (m_captureCallback) - m_captureCallback(0x03, loginfo); - creatcorrectconfig(0x03, IMAGE_GRAY); - param = GetFpgaparam(0x03,IMAGE_GRAY); - fu_correct.emplace(pool.enqueue([param](){creatLUTData(0x03,IMAGE_GRAY,param);})); - loginfo = "-----------600DPI Gray Correct Done----------- \r\n\r\n "; - if (m_captureCallback) - m_captureCallback(0x03, loginfo); -#endif + } while(fu_correct.size()) { fu_correct.front().get(); fu_correct.pop(); } - loginfo = "******Correct Done****** time " + std::to_string(std::chrono::duration(std::chrono::steady_clock::now() - _start).count())+"s"; + loginfo = "******Correct Done****** " +std::to_string( std::chrono::duration(std::chrono::steady_clock::now() - _start).count()) +"s"; if (m_captureCallback) m_captureCallback(0x03, loginfo); } diff --git a/device/gxx-linux/capimage/MonoCapturer.h b/device/gxx-linux/capimage/MonoCapturer.h index 136c76d..79c810d 100644 --- a/device/gxx-linux/capimage/MonoCapturer.h +++ b/device/gxx-linux/capimage/MonoCapturer.h @@ -41,12 +41,13 @@ public: m_captureCallback = callback; }; virtual void Fpga_regsAccess_reset(bool enable); + private: void configFPGAParam(int mode, int dpi); void openDevice(int dpi, int mode); void creatcorrectconfig(int dpi, int mode); bool saveLutImg(int dpi, int mode, bool black); - void correctcolor(); + void correctcolor(int correctmode); void fpga_reset(); void fpga_reload(); @@ -64,4 +65,5 @@ private: std::shared_ptr fpga_conf_done; bool bcorrecting; std::thread m_correctthread; + unsigned int m_fpgaversion; }; diff --git a/device/gxx-linux/capimage/SysInforTool.cpp b/device/gxx-linux/capimage/SysInforTool.cpp index 68219bd..7b15e4d 100644 --- a/device/gxx-linux/capimage/SysInforTool.cpp +++ b/device/gxx-linux/capimage/SysInforTool.cpp @@ -149,8 +149,8 @@ std::string SysInforTool::GetSysInfo() m_sysinfo.CPU = SCPU::CPU_3399; printf("Machine = %s CPU = %s \n", "Sys_Linux_Debian","CPU_3399"); } - m_sysinfo.MtType = SMBType::MB_DRV_8825; m_sysinfo.Cistype = HGCISType::CIS_DUNNAN_MONO_V0; + m_sysinfo.MtType = SMBType::MB_DRV_ANLU; char output[512]; get_system_output("uname -a",output,sizeof(output)); std::string ver(output); @@ -160,6 +160,7 @@ std::string SysInforTool::GetSysInfo() struct2json(j,m_sysinfo); std::ofstream o("/usr/local/huago/sysinfo.json"); o << std::setw(4) << j << std::endl; + o.close(); return j.dump(); } diff --git a/device/gxx-linux/capimage/correct_ultis.cpp b/device/gxx-linux/capimage/correct_ultis.cpp index 1774ccd..f32e45a 100644 --- a/device/gxx-linux/capimage/correct_ultis.cpp +++ b/device/gxx-linux/capimage/correct_ultis.cpp @@ -37,11 +37,7 @@ cv::Mat extractRepresentRow2(const cv::Mat &src) return BWbalenceSrc; } -#ifdef G300 -#define CHANNEL 432 -#else -#define CHANNEL 408 -#endif + cv::Mat loadLUT(const std::string& file) { cv::Mat dataFile = cv::imread(file, cv::IMREAD_ANYCOLOR); @@ -56,7 +52,7 @@ cv::Mat loadLUT(const std::string& file) else if (step == 14688 ||step== 22032 || step == 44064) channel = 432; //486 #else - channel = CHANNEL; + channel = 408; #endif cv::Mat lut(step / channel, 256, CV_8UC(channel)); memcpy(lut.data, dataFile.data, total); @@ -108,6 +104,7 @@ void correctColor(cv::Mat& src, int dpi, int mode,bool isText) if (access(path.c_str(), F_OK) != -1) { lutGrayMat = loadLUT(path); + //brightness(lutGrayMat); } else { @@ -128,17 +125,12 @@ void correctColor(cv::Mat& src, int dpi, int mode,bool isText) cv::LUT(image_temp(cv::Rect(i, 0, 1, image_temp.rows)), lutMat(cv::Rect(0, i, 256, 1)), image_temp(cv::Rect(i, 0, 1, image_temp.rows))); } - -void creatLUTData(int dpi , int mode,FPGAConfigParam param) -{ +void creatLUTData(int dpi , int mode,FPGAConfigParam param){ printf("eneter creatLUTData \n"); auto colormode = mode == 1 ? IMREAD_COLOR : IMREAD_GRAYSCALE; std::string blackPath = param.Flat_BwPath; std::string whitePath = param.Flat_WhitePath; std::string lutsavePath = param.LutPath; - printf("\n blackPath =%s \ - whitePath =%s \ - lutsavePath =%s \n",param.Flat_BwPath.c_str(),param.Flat_WhitePath.c_str(),param.LutPath.c_str()); cv::Mat lut; cv::Mat twMat = cv::imread(whitePath, IMREAD_ANYCOLOR); cv::Mat tbMat = cv::imread(blackPath, IMREAD_ANYCOLOR); @@ -244,6 +236,7 @@ void fittingLUT(const std::vector& points, uchar min_value, uchar max_val } } +#define CHANNEL 408 cv::Mat calcLUT(const cv::Mat& black, const cv::Mat& white, bool isTextCorrection) { std::vector w; @@ -410,7 +403,7 @@ cv::Mat createLUT(const std::vector& mats, bool isTextCorrect) } if (isTextCorrect) { - std::vector points_x = { 0, 25, 230, 255 }, points_y = { 0, 0, 255, 255 }; + std::vector points_x = { 0, 25, 205, 255 }, points_y = { 0, 0, 230, 255 }; std::vector coefficient = caculate(points_x, points_y); uchar buffer[256]; diff --git a/device/gxx-linux/capimage/correct_ultis.h b/device/gxx-linux/capimage/correct_ultis.h index 27859fd..95588f0 100644 --- a/device/gxx-linux/capimage/correct_ultis.h +++ b/device/gxx-linux/capimage/correct_ultis.h @@ -29,5 +29,3 @@ FPGAConfigParam GetFpgaparam(int dpi,int mode); void SaveFpgaparam(FPGAConfigParam& param); cv::Mat create_lut(const cv::Mat& black, const cv::Mat& white,int dpi, bool colormode); - -void correctColor(cv::Mat& src, int dpi, int mode,bool isText); \ No newline at end of file diff --git a/device/gxx-linux/capimage/gvideoisp1.cpp b/device/gxx-linux/capimage/gvideoisp1.cpp index 89ff4d8..e9df0f7 100644 --- a/device/gxx-linux/capimage/gvideoisp1.cpp +++ b/device/gxx-linux/capimage/gvideoisp1.cpp @@ -172,7 +172,6 @@ void* GVideoISP1::read_frame(int timeout) { LOG_TRACE(string_format("VIDIOC_QBUF sucess")); } LOG_TRACE(string_format("buf.index = %d,buf.addr = %p\n",buf.index,buffers[buf.index].start)); - printf("\n readframe size = %d ",buffers[buf.index].length); return buffers[buf.index].start; } diff --git a/device/gxx-linux/capimage/hgutils.cpp b/device/gxx-linux/capimage/hgutils.cpp index 48dfd06..a2b32d0 100644 --- a/device/gxx-linux/capimage/hgutils.cpp +++ b/device/gxx-linux/capimage/hgutils.cpp @@ -289,36 +289,10 @@ cv::Mat GetMergeMat(cv::Mat& mat, int width, int height, int type) return mat; } -cv::Mat GetStitchMat(int pixtype,int width,int height,cv::Mat& mat){ - cv::Mat dst; - cv::Mat ch_mats[3]; - int dstwidth, dstheight; - width = width /3 /(pixtype == 1? 3:1); - height *=3; - dstwidth = width * 3; - dstheight = height / 3; - if (pixtype == IMAGE_COLOR) - { - //mat = cv::Mat(m_height / 3, m_width * 9, CV_8UC1, imgdata); - dst = cv::Mat(dstheight, dstwidth, CV_8UC3); - ch_mats[2] = mat(cv::Rect(width * 3 * 1, 0, width * 3, height / 3)); //R 对应红通道 - ch_mats[1] = mat(cv::Rect(width * 3 * 2, 0, width * 3, height / 3)); //G 对应绿通道 - ch_mats[0] = mat(cv::Rect(width * 3 * 0, 0, width * 3, height / 3)); //B 对应蓝通道 - cv::merge(ch_mats, 3, dst); - for (int i = 0; i < 3; i++) - ch_mats[i].release(); - return dst.clone(); - } - else - { //gray - return mat; - } -} - //3399 敦南cis 300 600 拼接算法 -cv::Mat GetMergeMat(int dstwidth ,int dstheight,int type,cv::Mat& mat,std::uint32_t fpga_vs) +cv::Mat GetMergeMat(int dstwidth ,int dstheight,int type,cv::Mat& mat,unsigned int fpgaversion) { - return CImageMerge().MergeImage(type==CV_8UC3,mat,dstwidth,dstheight,0x90001); + return CImageMerge().MergeImage(type==CV_8UC3,mat,dstwidth,dstheight,fpgaversion); } void savescannerinfo(ScannerNativeParam params) diff --git a/device/gxx-linux/capimage/hgutils.h b/device/gxx-linux/capimage/hgutils.h index 471c30d..0705df1 100644 --- a/device/gxx-linux/capimage/hgutils.h +++ b/device/gxx-linux/capimage/hgutils.h @@ -19,9 +19,8 @@ cv::Mat GetMergeMat(void* data,int width ,int height,int type); cv::Mat GetMergeMat(cv::Mat& mat,int width ,int height,int type); -cv::Mat GetMergeMat(int dstwidth ,int dstheight,int type,cv::Mat& mat,std::uint32_t fpga_vs); -cv::Mat GetStitchMat(int pixtype,int width,int height,cv::Mat& mat); +cv::Mat GetMergeMat(int dstwidth ,int dstheight,int type,cv::Mat& mat,unsigned int fpgaversion=0x00090001); void correctColor(cv::Mat src, bool enhance); diff --git a/device/gxx-linux/capimage/jsonconfig.cpp b/device/gxx-linux/capimage/jsonconfig.cpp index 0f67b80..9992206 100644 --- a/device/gxx-linux/capimage/jsonconfig.cpp +++ b/device/gxx-linux/capimage/jsonconfig.cpp @@ -77,6 +77,7 @@ void jsonconfig::savecisconfig(HGCorrectConfigs configs) std::ofstream o(JSON_CORRECTFILE_PATH); o << std::setw(4) << m_json << std::endl; + o.close(); } HGCorrectConfigs jsonconfig::getcorrectconfigs() @@ -111,7 +112,7 @@ HGCorrectConfigs jsonconfig::getcorrectconfigs() i.seekg(pos); json m_json; i >> m_json; - + i.close(); cfs.colorCorrect.sp = cfs.color.sp = SP_COLOR_DEFAULT; cfs.grayCorrect.sp = cfs.gray.sp = SP_GRAY_DEFAULT; std::cout <<"GET GET GET GET GET GET" < lc(mtx); + ScannerNativeParam snp; + if (access(JSON_SCANNER_INFO_DIR, 0) == -1) { auto ret = mkdir(JSON_SCANNER_INFO_DIR, 0777); @@ -243,14 +250,13 @@ ScannerNativeParam jsonconfig::getscannerinfo() printf("make dir failed .path=%s \n", JSON_SCANNER_INFO_DIR); } } - - if (access(JSON_SCANNER_INFO_FILE, F_OK) != 0) + if (access(JSON_SCANNER_INFO_FILE, 0) == -1) { + printf("\nerror !!! file no exist"); snp = getdefaultscannerinfo(); savescannerinfo(snp); return snp; } - std::ifstream i(JSON_SCANNER_INFO_FILE); auto pos = i.tellg(); @@ -260,6 +266,7 @@ ScannerNativeParam jsonconfig::getscannerinfo() //printf("file length =%d ", i.tellg()); if (i.tellg() <= 2) { + printf("\nerror !!! file data error"); snp = getdefaultscannerinfo(); savescannerinfo(snp); return snp; @@ -352,9 +359,9 @@ ScannerNativeParam jsonconfig::getscannerinfo() if(!m_json[S_INFO_SPEEDMODE].is_null()) - m_json[S_INFO_SPEEDMODE].get_to(snp.speedmode); + m_json[S_INFO_SPEEDMODE].get_to(snp.speedmode),printf("\n %s Get speedmode value = %d",JSON_SCANNER_INFO_FILE,snp.speedmode); else - snp.speedmode=0; + snp.speedmode=0,printf("\n %s Get speedmode failed ",JSON_SCANNER_INFO_FILE); if(!m_json[S_INFO_PID].is_null()) m_json[S_INFO_PID].get_to(snp.Pid); @@ -362,12 +369,8 @@ ScannerNativeParam jsonconfig::getscannerinfo() { #ifdef G100 snp.Pid = 0x139; - #elif defined G200 - snp.Pid = 0x239; - #elif defined G300 - snp.Pid = 0x339; #else - snp.Pid = 0x439; + snp.Pid = 0x239; #endif } @@ -375,6 +378,21 @@ ScannerNativeParam jsonconfig::getscannerinfo() m_json[S_INFO_VID].get_to(snp.Vid); else snp.Vid = 0x3072; + + if(!m_json[S_INFO_CHUZHI_MOTOR_SPEED_200].is_null()) + m_json[S_INFO_CHUZHI_MOTOR_SPEED_200].get_to(snp.chu_motor_speed_200); + else + snp.chu_motor_speed_200 = 300; + + if(!m_json[S_INFO_CHUZHI_MOTOR_SPEED_300].is_null()) + m_json[S_INFO_CHUZHI_MOTOR_SPEED_300].get_to(snp.chu_motor_speed_300); + else + snp.chu_motor_speed_300 = 200; + + if(!m_json[S_INFO_CHUZHI_MOTOR_SPEED_600].is_null()) + m_json[S_INFO_CHUZHI_MOTOR_SPEED_600].get_to(snp.chu_motor_speed_600); + else + snp.chu_motor_speed_600 = 100; //printf("vid = %d pid =%d \n",snp.Vid,snp.Pid ); return snp; @@ -396,25 +414,17 @@ ScannerNativeParam jsonconfig::getdefaultscannerinfo() param.color_sp=0x27C; param.speedmode = 100; param.Pid = 0x0239; -#elif defined G100 +#else param.gray_sp=0x822; //G200 140 ppm 0x27c 0x781 G100 100 ppm 0x2B6 0x822 param.color_sp=0x2B6; param.speedmode = 70; param.Pid = 0x0139; -#elif defined G300 - param.gray_sp=0x822; - param.color_sp=0x2B6; - param.speedmode = 40; - param.Pid = 0x0339; -#else - param.gray_sp=0x822; - param.color_sp=0x2B6; - param.speedmode = 50; - param.Pid = 0x0439; #endif param.Vid = 0x3072; param.sleeptime=10800; param.clr_maxbright = param.gray_maxbright = 200; - + param.chu_motor_speed_200 = 300; + param.chu_motor_speed_300 = 200; + param.chu_motor_speed_600 = 100; return param; } diff --git a/device/gxx-linux/capimage/jsonconfig.h b/device/gxx-linux/capimage/jsonconfig.h index 1a43092..410e5d7 100644 --- a/device/gxx-linux/capimage/jsonconfig.h +++ b/device/gxx-linux/capimage/jsonconfig.h @@ -2,7 +2,6 @@ #include "json.hpp" #include "commondef.h" #include - using json = nlohmann::json; class jsonconfig diff --git a/device/gxx-linux/capimage/scannersysinfo.h b/device/gxx-linux/capimage/scannersysinfo.h index 23d8ac1..56703f7 100644 --- a/device/gxx-linux/capimage/scannersysinfo.h +++ b/device/gxx-linux/capimage/scannersysinfo.h @@ -1,6 +1,6 @@ #pragma once #include - +#include "commondef.h" enum class SysType { Sys_Linux_Debian=1, diff --git a/device/gxx-linux/capimage/xmake.lua b/device/gxx-linux/capimage/xmake.lua index 8465f32..09de6fe 100644 --- a/device/gxx-linux/capimage/xmake.lua +++ b/device/gxx-linux/capimage/xmake.lua @@ -5,6 +5,6 @@ target("capimage") add_files("*.cpp") add_deps("regs", "deviceio", "conf", "applog", {public = true}) add_includedirs(".", { public = true}) - add_links("opencv_core", "opencv_imgcodecs", "opencv_highgui", "opencv_imgproc", { public = true }) + add_links("opencv_core", "opencv_highgui", "opencv_imgproc", { public = true }) add_syslinks("pthread") add_packages("common") \ No newline at end of file diff --git a/device/gxx-linux/deviceio/DevUtil.h b/device/gxx-linux/deviceio/DevUtil.h index 4ec2b08..3c3d261 100644 --- a/device/gxx-linux/deviceio/DevUtil.h +++ b/device/gxx-linux/deviceio/DevUtil.h @@ -3,6 +3,7 @@ #include #include +#define G300 template void write_dev(std::string path, T value) @@ -20,7 +21,7 @@ enum PORTS Start = 171, Stop = 49, Power = 5, - Fpga_Load = 8, + Fpga_Load = 70, #ifndef G300 Power_12v_Off = 12, diff --git a/device/gxx-linux/deviceio/Gpio.cpp b/device/gxx-linux/deviceio/Gpio.cpp index 92d046f..4842f6d 100644 --- a/device/gxx-linux/deviceio/Gpio.cpp +++ b/device/gxx-linux/deviceio/Gpio.cpp @@ -4,6 +4,10 @@ #include "Gpio.h" #include "DevUtil.h" #include "stringex.hpp" +#include +#include +#include +#include #define IOPATH "%s/gpio%d/%s" @@ -22,8 +26,16 @@ Gpio::Gpio(int port) path_edge = string_format(IOPATH, path_gpiobase.c_str(), port, path_edge.c_str()); path_direction = string_format(IOPATH, path_gpiobase.c_str(), port, path_direction.c_str()); path_active_low = string_format(IOPATH, path_gpiobase.c_str(), port, path_active_low.c_str()); + char fpath[128]{}; + sprintf(fpath,"/sys/class/gpio/gpio%d/value",port); + printf("Gpio::Gpio(int port = %d) \n",port); + gpio_fd = open(fpath,O_RDWR); } +Gpio::~Gpio() +{ + close(gpio_fd); +} int Gpio::getPort() { return port; @@ -31,7 +43,13 @@ int Gpio::getPort() void Gpio::setValue(GpioLevel level) { - write_dev(path_value, level); + //write_dev(path_value, level); + if(port == 153 || port == 150) + printf("\n Gpio %d setvalue %d ",port,level==Low?0:1); + if(level == Low) + write(gpio_fd,"0\n",2); + else + write(gpio_fd,"1\n",2); } Gpio::GpioLevel Gpio::getValue() { @@ -45,6 +63,8 @@ std::string Gpio::getDirection() void Gpio::setDirection(std::string direction) { + if(port == 153 || port == 150) + printf("\n Gpio %d setDirection %s ",port,direction.c_str()); write_dev(path_direction, direction); } diff --git a/device/gxx-linux/deviceio/Gpio.h b/device/gxx-linux/deviceio/Gpio.h index 1ee375a..f08a5d8 100644 --- a/device/gxx-linux/deviceio/Gpio.h +++ b/device/gxx-linux/deviceio/Gpio.h @@ -11,6 +11,7 @@ public: }; Gpio(int port); + ~Gpio(); int getPort(); void setValue(GpioLevel level); GpioLevel getValue(); @@ -41,6 +42,7 @@ private: std::string path_edge = "edge"; std::string path_direction = "direction"; std::string path_active_low = "active_low"; + int gpio_fd; }; class GpioOut : public Gpio diff --git a/device/gxx-linux/deviceio/PinMonitor.cpp b/device/gxx-linux/deviceio/PinMonitor.cpp index 2c7249e..b952276 100644 --- a/device/gxx-linux/deviceio/PinMonitor.cpp +++ b/device/gxx-linux/deviceio/PinMonitor.cpp @@ -15,18 +15,6 @@ PinMonitor::PinMonitor(unsigned int pinNum, std::function call_back) this->call_back = call_back; thread_monitor = std::thread(&PinMonitor::monitor, this); //printf("PinMonitor threadid = %d \n",thread_monitor.get_id()); - sched_param thparm; - int priority=sched_get_priority_max(SCHED_FIFO); - if(priority==-1) - { - printf("sched_get_priority_max error \n"); - } - thparm.sched_priority = priority; - if(pthread_setschedparam(thread_monitor.native_handle(),SCHED_FIFO,&thparm)) - { - printf("failed to error set pthread_setschedparam \n"); - } - } PinMonitor::~PinMonitor() diff --git a/device/gxx-linux/deviceio/PinMonitor.h b/device/gxx-linux/deviceio/PinMonitor.h index 5032c71..60fd831 100644 --- a/device/gxx-linux/deviceio/PinMonitor.h +++ b/device/gxx-linux/deviceio/PinMonitor.h @@ -11,7 +11,7 @@ public: private: void monitor(); - //sched_param thparm; + Gpio pin; std::function call_back; std::thread thread_monitor; diff --git a/device/gxx-linux/deviceio/xmake.lua b/device/gxx-linux/deviceio/xmake.lua index babe91f..e234c1c 100644 --- a/device/gxx-linux/deviceio/xmake.lua +++ b/device/gxx-linux/deviceio/xmake.lua @@ -5,5 +5,4 @@ target("deviceio") add_syslinks("pthread") add_files("*.cpp") add_includedirs(".", { public = true}) - add_deps("applog") add_packages("common") diff --git a/device/gxx-linux/display/DisplayCenter.cpp b/device/gxx-linux/display/DisplayCenter.cpp new file mode 100644 index 0000000..cb44696 --- /dev/null +++ b/device/gxx-linux/display/DisplayCenter.cpp @@ -0,0 +1,56 @@ +#include "DisplayCenter.h" +#include "LCDDisplay.h" + +DisplayCenter::DisplayCenter():m_lcd(new LCDDisplay()) + ,brun(false) +{ + m_showthread.reset(new std::thread(&DisplayCenter::runloop,this)); + m_distype = DisType::Dis_Idel; +} + +DisplayCenter::~DisplayCenter() +{ + brun = false; + if(m_showthread.get()&& m_showthread->joinable()) + { + m_showthread->join(); + m_showthread.reset(); + } + + if(!m_msgs.IsShutDown()) + m_msgs.ShutDown(); + + m_lcd.reset(); +} + +void DisplayCenter::PutMsg(DisType distype,int pagenum,ClearScreen clearscreen) +{ + m_msgs.Put({distype,clearscreen,(unsigned int )pagenum,""}); + m_distype = distype; + printf("\n ----- distype = %d ",distype); +} + +void DisplayCenter::ResetMsgQueue() +{ + m_msgs.Clear(); +} + +void DisplayCenter::runloop() +{ + brun = true; + while (brun) + { + if(m_msgs.Size()>0) + { + auto msg= m_msgs.Take(); + m_lcd->DisplayState(msg.distype,msg.pagenum,msg.clearscree); + } + else + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + } +} + +DisType DisplayCenter::getcurdistype() +{ + return m_distype; +} \ No newline at end of file diff --git a/device/gxx-linux/display/DisplayCenter.h b/device/gxx-linux/display/DisplayCenter.h new file mode 100644 index 0000000..efe2294 --- /dev/null +++ b/device/gxx-linux/display/DisplayCenter.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include "BlockingQueue.h" +#include "Displaydef.h" + +class LCDDisplay; + +class DisplayCenter +{ +public: + DisplayCenter(); + ~DisplayCenter(); + void PutMsg(DisType distype,int pagenum,ClearScreen clearscreen); + void ResetMsgQueue(); + DisType getcurdistype(); +private: + struct MsgPair{ + DisType distype; + ClearScreen clearscree; + unsigned int pagenum; + std::string infomsg; + }; + void runloop(); +private: + BlockingQueue m_msgs; + std::shared_ptr m_showthread; + std::shared_ptr m_lcd; + volatile DisType m_distype; + bool brun; +}; \ No newline at end of file diff --git a/device/gxx-linux/display/Displaydef.h b/device/gxx-linux/display/Displaydef.h new file mode 100644 index 0000000..e617cd9 --- /dev/null +++ b/device/gxx-linux/display/Displaydef.h @@ -0,0 +1,114 @@ +#pragma once +#include +#include +#include "HgLCDfont.h" + +enum class DisType{ + Dis_Unkown, + Dis_Init,//启动欢迎界面 + Dis_Welcome, + Dis_Idel,//就绪 + Dis_Scan, + Dis_Err_JamIn, + Dis_Err_DoubleFeed, + Dis_Err_PaperScrew, + Dis_Err_Stable, + Dis_Err_AqrImgTimeout, + Dis_Err_CoverOpen, + Dis_Err_JamOut, + Dis_Err_HandModeJam, + Dis_Err_FeedError, + Dis_Err_NoPaper, + Dis_Err_DogEar, + Dis_Err_Size, + Dis_Set_PollPaperIntensity, + Dis_Set_PollPI_High, + Dis_Set_PollPI_Mid, + Dis_Set_PollPI_Low, + Dis_Count_Page, + Dis_Scan_Page, + Dis_Set_ClearPaperPass, + Dis_Set_Count, + Dis_Set_SleepMode, + Dis_Set_SleepMode_5M, + Dis_Set_SleepMode_10M, + Dis_Set_SleepMode_20M, + Dis_Set_SleepMode_30M, + Dis_Set_SleepMode_1H, + Dis_Set_SleepMode_2H, + Dis_Set_SleepMode_4H, + Dis_Set_SleepMode_NEVER, + Dis_Set_Poweroff, + Dis_Set_Return, + Dis_HandMode, + Dis_Set_Item_Return, + Dis_Set_TrayPosition, + Dis_Set_TrayPosition_Low, + Dis_Set_TrayPosition_Mid, + Dis_Set_TrayPosition_High, + Dis_Device_Lock, +}; + +enum class DisDrawtype +{ + DD_All, + DD_TopLeft, + DD_BotRight +}; + +enum class ClearScreen +{ + All, + TOP, + BOT, +}; + +struct DisInfo{ + unsigned char page; + unsigned char col; + DisDrawtype drawtype; + std::vector str; +}; + +static std::map map_Display={ + {DisType::Dis_Welcome,{1,1,DisDrawtype::DD_All,std::vector(f_logo,f_logo+sizeof(f_logo))}}, + {DisType::Dis_Init,{1,1,DisDrawtype::DD_All,std::vector(f_welcome,f_welcome+sizeof(f_welcome))}}, + {DisType::Dis_Idel,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_ready,f_ready+sizeof(f_ready))}}, + {DisType::Dis_Scan,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_scan,f_scan+sizeof(f_scan))}}, + {DisType::Dis_Set_ClearPaperPass,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_clearpaperpass,f_clearpaperpass+sizeof(f_clearpaperpass))}}, + {DisType::Dis_Set_Count,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_countmode,f_countmode+sizeof(f_countmode))}}, + {DisType::Dis_Err_DoubleFeed,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_doublefeed,f_doublefeed+sizeof(f_doublefeed))}}, + {DisType::Dis_Err_Stable,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_stable,f_stable+sizeof(f_stable))}}, + {DisType::Dis_Err_CoverOpen,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_coveropen,f_coveropen+sizeof(f_coveropen))}}, + {DisType::Dis_Err_JamIn,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_paperjam,f_paperjam+sizeof(f_paperjam))}}, + {DisType::Dis_Err_JamOut,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_paperjam,f_paperjam+sizeof(f_paperjam))}}, + {DisType::Dis_Err_HandModeJam,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_handmodepaperjam,f_handmodepaperjam+sizeof(f_handmodepaperjam))}}, + {DisType::Dis_Err_PaperScrew,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_paperscrew,f_paperscrew+sizeof(f_paperscrew))}}, + {DisType::Dis_Err_FeedError,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_feederror,f_feederror+sizeof(f_feederror))}}, + {DisType::Dis_Err_AqrImgTimeout,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_aqrimgtimeout,f_aqrimgtimeout+sizeof(f_aqrimgtimeout))}}, + {DisType::Dis_Err_DogEar,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_dogear,f_dogear+sizeof(f_dogear))}}, + {DisType::Dis_Err_Size,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_size,f_size+sizeof(f_size))}}, + {DisType::Dis_Set_PollPaperIntensity,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_pollpaperintensity,f_pollpaperintensity+sizeof(f_pollpaperintensity))}}, + {DisType::Dis_Set_PollPI_High,{3,96,DisDrawtype::DD_BotRight,std::vector(f_intensityHigh,f_intensityHigh+sizeof(f_intensityHigh))}}, + {DisType::Dis_Set_PollPI_Mid,{3,96,DisDrawtype::DD_BotRight,std::vector(f_intensityMid,f_intensityMid+sizeof(f_intensityMid))}}, + {DisType::Dis_Set_PollPI_Low,{3,96,DisDrawtype::DD_BotRight,std::vector(f_intensityLow,f_intensityLow+sizeof(f_intensityLow))}}, + + {DisType::Dis_Set_TrayPosition,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_trayposition,f_trayposition+sizeof(f_trayposition))}}, + {DisType::Dis_Set_TrayPosition_High,{3,96,DisDrawtype::DD_BotRight,std::vector(f_intensityHigh,f_intensityHigh+sizeof(f_intensityHigh))}}, + {DisType::Dis_Set_TrayPosition_Mid,{3,96,DisDrawtype::DD_BotRight,std::vector(f_intensityMid,f_intensityMid+sizeof(f_intensityMid))}}, + {DisType::Dis_Set_TrayPosition_Low,{3,96,DisDrawtype::DD_BotRight,std::vector(f_traypositionLow,f_traypositionLow+sizeof(f_traypositionLow))}}, + + {DisType::Dis_Count_Page,{3,112,DisDrawtype::DD_BotRight,std::vector(f_page,f_page+sizeof(f_page))}}, + {DisType::Dis_Scan_Page,{3,112,DisDrawtype::DD_BotRight,std::vector(f_page,f_page+sizeof(f_page))}}, + {DisType::Dis_Err_NoPaper,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_nopaper,f_nopaper+sizeof(f_nopaper))}}, + {DisType::Dis_Set_SleepMode,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_sleepmode,f_sleepmode+sizeof(f_sleepmode))}}, + // {DisType::Dis_Set_SleepMode_30M,{3,64,DisDrawtype::DD_BotRight,std::vector(f_30min,f_30min+sizeof(f_30min))}}, + // {DisType::Dis_Set_SleepMode_1H,{3,80,DisDrawtype::DD_BotRight,std::vector(f_1hour,f_1hour+sizeof(f_1hour))}}, + // {DisType::Dis_Set_SleepMode_2H,{3,80,DisDrawtype::DD_BotRight,std::vector(f_2hour,f_2hour+sizeof(f_2hour))}}, + {DisType::Dis_Set_SleepMode_NEVER,{3,80,DisDrawtype::DD_BotRight,std::vector(f_never,f_never+sizeof(f_never))}}, + {DisType::Dis_Set_Return,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_return,f_return+sizeof(f_return))}}, + {DisType::Dis_Set_Poweroff,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_powerof,f_powerof+sizeof(f_powerof))}}, + {DisType::Dis_HandMode,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_handmode,f_handmode+sizeof(f_handmode))}}, + {DisType::Dis_Set_Item_Return,{3,96,DisDrawtype::DD_BotRight,std::vector(f_return,f_return+sizeof(f_return))}}, + {DisType::Dis_Device_Lock,{1,1,DisDrawtype::DD_TopLeft,std::vector(f_deviceLock,f_deviceLock+sizeof(f_deviceLock))}}, +}; diff --git a/device/gxx-linux/display/HgLCDfont.h b/device/gxx-linux/display/HgLCDfont.h new file mode 100644 index 0000000..848c5cf --- /dev/null +++ b/device/gxx-linux/display/HgLCDfont.h @@ -0,0 +1,433 @@ +#pragma once + +/*就绪*/ +static unsigned char f_ready[]={ +0x04,0xE4,0x25,0x26,0x24,0xE4,0x04,0x20,0x20,0xFF,0x20,0xE2,0x2C,0x20,0x20,0x00, +0x10,0x4B,0x82,0x7E,0x02,0x0B,0x90,0x60,0x1C,0x03,0x00,0x3F,0x40,0x40,0x70,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x20,0x30,0xAC,0x63,0x10,0x20,0x24,0x24,0xA4,0x7F,0x24,0x34,0x28,0x26,0x20,0x00, +0x22,0x67,0x22,0x12,0x12,0x04,0x02,0xFF,0x49,0x49,0x49,0x49,0xFF,0x00,0x00,0x00 +}; + +/*图标*/ +static unsigned char f_logo[]={ +0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, +0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x03, +0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xF0,0xFC,0xFC, +0x3C,0x3F,0x3F,0x3F,0x3C,0x3C,0x3C,0x00,0x00,0x00,0x00,0xC0,0xF0,0xFC,0xFC,0x3C, +0x3F,0x3F,0x3C,0xFC,0xFC,0xF0,0xC0,0x00,0x00,0x00,0x00,0xF0,0xFC,0x3C,0x3F,0x3F, +0x3F,0x3C,0x3C,0x3C,0x00,0x00,0x00,0xC0,0xF0,0xFC,0xFC,0x3F,0x3F,0x3F,0x3F,0x3C, +0x3C,0xFC,0x30,0x00,0x00,0x00,0x00,0x00,0xC3,0xFF,0xFF,0xFF,0xFF,0xFC,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFC,0xC0,0x00,0x00,0x00,0x03,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0xF0,0xC0,0xC0,0xC0,0xC0,0xF0,0xFF,0xFF,0x00,0x00,0x00,0x00, +0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0xC0,0xFC, +0xFF,0x3F,0x00,0x03,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x0F,0x00, +0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0xC0,0xFF,0xFF,0x03,0x00,0x00, +0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0xF0,0xC0, +0xC0,0xC0,0x00,0x00,0x00,0x00,0xFC,0xFF,0x0F,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0x03,0x00,0x00,0x3F,0xFF,0xFF,0x00, +0x00,0x00,0x00,0x00,0x00,0xFF,0x03,0x0F,0x3F,0xFF,0xFC,0x00,0x00,0x00,0xFF,0xFF, +0xFF,0xFF,0xFF,0xFF,0x07,0x01,0x01,0x01,0x01,0x07,0xFF,0xFF,0x00,0x00,0x00,0x00, +0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x7F,0x00,0x00,0x80,0xFF,0xFF, +0xF9,0xE0,0xE0,0xE0,0xE0,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0xFF,0xFF,0xFF,0xE0,0x00, +0x00,0x00,0x07,0x07,0x07,0xFF,0xFF,0x00,0x00,0x00,0x01,0xFF,0xFF,0xE0,0x00,0x00, +0x00,0x00,0x00,0x00,0x80,0xFF,0xFF,0x1F,0x00,0x00,0x00,0x00,0x01,0x01,0x07,0x07, +0x1F,0xFF,0xFF,0xF8,0x00,0x00,0x7F,0xFF,0xF8,0x80,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0xE0,0xFE,0xFF,0xFF,0xE0,0xE0,0xE0,0xE0,0xF9,0xFF,0xFE, +0x80,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x01,0x1F,0xF8,0x80,0x80,0xFF,0xFF, +0x7F,0x7F,0x7F,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x7F,0x00,0x00,0x00,0x00, +0x01,0x1F,0x7F,0x7E,0x78,0x78,0x7E,0x7E,0x1F,0x07,0x00,0x00,0x60,0x7F,0x1F,0x07, +0x01,0x01,0x01,0x01,0x01,0x01,0x07,0x7F,0x7F,0x60,0x00,0x01,0x07,0x1F,0x1F,0x7E, +0x7E,0x78,0x78,0x78,0x78,0x7F,0x7F,0x00,0x00,0x00,0x00,0x07,0x1F,0x1F,0x7E,0x7E, +0x78,0x78,0x7E,0x7E,0x7F,0x1F,0x01,0x00,0x00,0x00,0x00,0x78,0x78,0x78,0x78,0x7E, +0x7E,0x7F,0x1F,0x01,0x00,0x00,0x00,0x01,0x1F,0x7F,0x7E,0x7E,0x78,0x78,0x78,0x7E, +0x7E,0x1E,0x18,0x00,0x78,0x7F,0x7F,0x07,0x01,0x01,0x01,0x01,0x01,0x01,0x07,0x7F, +0x7F,0x78,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x1F,0x7F,0x7F,0x7F,0x7F +}; + + +/*欢迎使用*/ +static unsigned char f_welcome[] = { +0x04,0x24,0x44,0x84,0x64,0x9C,0x40,0x30,0x0F,0xC8,0x08,0x08,0x28,0x18,0x00,0x00, +0x10,0x08,0x06,0x01,0x82,0x4C,0x20,0x18,0x06,0x01,0x06,0x18,0x20,0x40,0x80,0x00, +0x40,0x40,0x42,0xCC,0x00,0x00,0xFC,0x04,0x02,0x00,0xFC,0x04,0x04,0xFC,0x00,0x00, +0x00,0x40,0x20,0x1F,0x20,0x40,0x4F,0x44,0x42,0x40,0x7F,0x42,0x44,0x43,0x40,0x00, +0x80,0x60,0xF8,0x07,0x04,0xE4,0x24,0x24,0x24,0xFF,0x24,0x24,0x24,0xE4,0x04,0x00, +0x00,0x00,0xFF,0x00,0x80,0x81,0x45,0x29,0x11,0x2F,0x41,0x41,0x81,0x81,0x80,0x00, +0x00,0x00,0xFE,0x22,0x22,0x22,0x22,0xFE,0x22,0x22,0x22,0x22,0xFE,0x00,0x00,0x00, +0x80,0x60,0x1F,0x02,0x02,0x02,0x02,0x7F,0x02,0x02,0x42,0x82,0x7F,0x00,0x00,0x00, +}; +/*清理纸道*/ +static unsigned char f_clearpaperpass[]={ +0x10,0x60,0x02,0x8C,0x00,0x44,0x54,0x54,0x54,0x7F,0x54,0x54,0x54,0x44,0x40,0x00, +0x04,0x04,0x7E,0x01,0x00,0x00,0xFF,0x15,0x15,0x15,0x55,0x95,0x7F,0x00,0x00,0x00, +0x04,0x84,0x84,0xFC,0x84,0x84,0x00,0xFE,0x92,0x92,0xFE,0x92,0x92,0xFE,0x00,0x00, +0x20,0x60,0x20,0x1F,0x10,0x10,0x40,0x44,0x44,0x44,0x7F,0x44,0x44,0x44,0x40,0x00, +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00, +0x40,0x40,0x42,0xCC,0x00,0x08,0xE9,0xAA,0xB8,0xA8,0xA8,0xAA,0xE9,0x08,0x00,0x00, +0x00,0x40,0x20,0x1F,0x20,0x40,0x5F,0x4A,0x4A,0x4A,0x4A,0x4A,0x5F,0x40,0x40,0x00 +}; + +/*计数*/ +static unsigned char f_countmode[] = { +0x40,0x40,0x42,0xCC,0x00,0x40,0x40,0x40,0x40,0xFF,0x40,0x40,0x40,0x40,0x40,0x00, +0x00,0x00,0x00,0x7F,0x20,0x10,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x90,0x52,0x34,0x10,0xFF,0x10,0x34,0x52,0x80,0x70,0x8F,0x08,0x08,0xF8,0x08,0x00, +0x82,0x9A,0x56,0x63,0x22,0x52,0x8E,0x00,0x80,0x40,0x33,0x0C,0x33,0x40,0x80,0x00 +}; + +static unsigned char f_dogear[] = { +0x10,0x10,0x10,0xFF,0x10,0x90,0x00,0xFC,0x44,0x44,0x44,0xC2,0x43,0x42,0x40,0x00, +0x04,0x44,0x82,0x7F,0x01,0x80,0x60,0x1F,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x20,0x10,0xE8,0x24,0x27,0x24,0x24,0xE4,0x24,0x34,0x2C,0x20,0xE0,0x00,0x00,0x00, +0x80,0x60,0x1F,0x09,0x09,0x09,0x09,0x7F,0x09,0x09,0x49,0x89,0x7F,0x00,0x00,0x00, +}; + +static unsigned char f_size[] = { +0x00,0x00,0x00,0xFE,0x42,0x42,0x42,0x42,0xC2,0x42,0x42,0x42,0x7E,0x00,0x00,0x00, +0x80,0x40,0x30,0x0F,0x00,0x00,0x00,0x00,0x03,0x0C,0x10,0x20,0x40,0x80,0x80,0x00, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,0x10,0x00, +0x00,0x00,0x00,0x01,0x06,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x02,0x02,0x02,0x82,0x42,0xF2,0x0E,0x42,0x82,0x02,0x02,0x02,0x00,0x00, +0x10,0x08,0x04,0x02,0x01,0x00,0x00,0xFF,0x00,0x00,0x00,0x01,0x02,0x0C,0x00,0x00, +0x10,0x08,0x04,0x87,0x6C,0x14,0x84,0x94,0x88,0x87,0x84,0xEC,0x94,0x84,0x84,0x00, +0x04,0x02,0x01,0xFF,0x00,0x00,0x00,0x02,0x0C,0x40,0x80,0x7F,0x00,0x00,0x00,0x00, +}; + +/*双张*/ +static unsigned char f_doublefeed[] = { +0x04,0x34,0xC4,0x04,0xC4,0x3C,0x00,0x04,0xFC,0x04,0x04,0x04,0xC4,0x3C,0x00,0x00, +0x40,0x30,0x0C,0x03,0x0C,0x30,0x80,0x40,0x20,0x13,0x0C,0x13,0x20,0x40,0x80,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x02,0xE2,0x22,0x22,0x3E,0x80,0x80,0xFF,0x80,0xA0,0x90,0x88,0x86,0x80,0x80,0x00, +0x00,0x43,0x82,0x42,0x3E,0x00,0x00,0xFF,0x40,0x21,0x06,0x08,0x10,0x20,0x40,0x00 +}; + +/*订书针*/ +static unsigned char f_stable[] = { +0x10,0x10,0xD0,0xFF,0x90,0x50,0x20,0x50,0x4C,0x43,0x4C,0x50,0x20,0x40,0x40,0x00, +0x04,0x03,0x00,0xFF,0x00,0x41,0x44,0x58,0x41,0x4E,0x60,0x58,0x47,0x40,0x40,0x00, +0x10,0x60,0x02,0x8C,0x00,0xFE,0x02,0xF2,0x02,0xFE,0x00,0xF8,0x00,0xFF,0x00,0x00, +0x04,0x04,0x7E,0x01,0x80,0x47,0x30,0x0F,0x10,0x27,0x00,0x47,0x80,0x7F,0x00,0x00, +0x42,0x62,0x52,0x4A,0xC6,0x42,0x52,0x62,0xC2,0x00,0xF8,0x00,0x00,0xFF,0x00,0x00, +0x40,0xC4,0x44,0x44,0x7F,0x24,0x24,0x24,0x20,0x00,0x0F,0x40,0x80,0x7F,0x00,0x00, +0x40,0x40,0x42,0xCC,0x00,0x00,0x04,0x04,0x04,0x04,0xFC,0x04,0x04,0x04,0x04,0x00, +0x00,0x00,0x00,0x7F,0x20,0x10,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x08,0x08,0x08,0x08,0xFF,0x08,0x08,0x08,0xF9,0x02,0x04,0x00,0x00,0x00, +0x01,0x01,0x01,0x01,0x01,0x01,0xFF,0x01,0x01,0x01,0x21,0x41,0x21,0x1F,0x00,0x00, +0x40,0x20,0x38,0xE7,0x24,0x24,0x44,0x40,0x40,0x40,0xFF,0x40,0x40,0x40,0x40,0x00, +0x01,0x01,0x01,0x7F,0x21,0x11,0x09,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00, +}; + +/*开盖*/ +static unsigned char f_coveropen[] = { +0x40,0x40,0x42,0xCC,0x00,0x40,0xA0,0x9E,0x82,0x82,0x82,0x9E,0xA0,0x20,0x20,0x00, +0x00,0x00,0x00,0x3F,0x90,0x88,0x40,0x43,0x2C,0x10,0x28,0x46,0x41,0x80,0x80,0x00, +0x80,0x90,0x90,0x48,0x4C,0x57,0x24,0x24,0x24,0x54,0x4C,0x44,0x80,0x80,0x80,0x00, +0x00,0x00,0x00,0xFF,0x49,0x49,0x49,0x7F,0x49,0x49,0x49,0xFF,0x00,0x00,0x00,0x00, +0x80,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x80,0x00, +0x00,0x80,0x40,0x30,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00, +0x00,0x04,0x24,0x24,0x25,0x26,0x24,0xFC,0x24,0x26,0x25,0x24,0x24,0x04,0x00,0x00, +0x81,0x81,0xF9,0x89,0x89,0xF9,0x89,0x89,0x89,0xF9,0x89,0x89,0xF9,0x81,0x81,0x00 +}; + +/*手动模式卡纸*/ +static unsigned char f_handmodepaperjam[] = { +0x00,0x00,0x24,0x24,0x24,0x24,0x24,0xFC,0x22,0x22,0x22,0x23,0x22,0x00,0x00,0x00, +0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,/*"手",0*/ +0x40,0x44,0xC4,0x44,0x44,0x44,0x40,0x10,0x10,0xFF,0x10,0x10,0x10,0xF0,0x00,0x00, +0x10,0x3C,0x13,0x10,0x14,0xB8,0x40,0x30,0x0E,0x01,0x40,0x80,0x40,0x3F,0x00,0x00,/*"动",1*/ +0x10,0x10,0xD0,0xFF,0x90,0x14,0xE4,0xAF,0xA4,0xA4,0xA4,0xAF,0xE4,0x04,0x00,0x00, +0x04,0x03,0x00,0xFF,0x00,0x89,0x4B,0x2A,0x1A,0x0E,0x1A,0x2A,0x4B,0x88,0x80,0x00,/*"模",2*/ +0x10,0x10,0x90,0x90,0x90,0x90,0x90,0x10,0x10,0xFF,0x10,0x10,0x11,0x16,0x10,0x00, +0x00,0x20,0x60,0x20,0x3F,0x10,0x10,0x10,0x00,0x03,0x0C,0x10,0x20,0x40,0xF8,0x00,/*"式",3*/ +0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x44,0x44,0x44,0x44,0x44,0x44,0x40,0x40,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x02,0x04,0x08,0x10,0x00,0x00,0x00,/*"卡",4*/ +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00,/*"纸",5*/ +}; + +/*手动模式*/ +static unsigned char f_handmode[] = { +0x00,0x00,0x24,0x24,0x24,0x24,0x24,0xFC,0x22,0x22,0x22,0x23,0x22,0x00,0x00,0x00, +0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00, +0x40,0x44,0xC4,0x44,0x44,0x44,0x40,0x10,0x10,0xFF,0x10,0x10,0x10,0xF0,0x00,0x00, +0x10,0x3C,0x13,0x10,0x14,0xB8,0x40,0x30,0x0E,0x01,0x40,0x80,0x40,0x3F,0x00,0x00, +0x10,0x10,0xD0,0xFF,0x90,0x14,0xE4,0xAF,0xA4,0xA4,0xA4,0xAF,0xE4,0x04,0x00,0x00, +0x04,0x03,0x00,0xFF,0x00,0x89,0x4B,0x2A,0x1A,0x0E,0x1A,0x2A,0x4B,0x88,0x80,0x00, +0x10,0x10,0x90,0x90,0x90,0x90,0x90,0x10,0x10,0xFF,0x10,0x10,0x11,0x16,0x10,0x00, +0x00,0x20,0x60,0x20,0x3F,0x10,0x10,0x10,0x00,0x03,0x0C,0x10,0x20,0x40,0xF8,0x00, +}; + +/*纸张歪斜*/ +static unsigned char f_paperscrew[] = { +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00, +0x02,0xE2,0x22,0x22,0x3E,0x80,0x80,0xFF,0x80,0xA0,0x90,0x88,0x86,0x80,0x80,0x00, +0x00,0x43,0x82,0x42,0x3E,0x00,0x00,0xFF,0x40,0x21,0x06,0x08,0x10,0x20,0x40,0x00, +0x00,0x42,0x42,0x22,0x22,0x12,0x0A,0x7E,0x02,0x12,0x12,0x22,0x22,0x42,0x00,0x00, +0x40,0x41,0x41,0x7D,0x41,0x41,0x41,0x7F,0x49,0x49,0x49,0x49,0x49,0x41,0x40,0x00, +0x20,0x10,0x28,0x24,0xE3,0x24,0x28,0x10,0x00,0x22,0xCC,0x00,0xFF,0x00,0x00,0x00, +0x20,0x11,0x4D,0x81,0x7F,0x01,0x05,0x19,0x00,0x02,0x02,0x02,0xFF,0x01,0x01,0x00 +}; + +/*卡纸*/ +static unsigned char f_paperjam[] = { +0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x44,0x44,0x44,0x44,0x44,0x44,0x40,0x40,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x02,0x04,0x08,0x10,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00 +}; + +/*卡纸001*/ +static unsigned char f_paperjam001[] = { +0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x44,0x44,0x44,0x44,0x44,0x44,0x40,0x40,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x02,0x04,0x08,0x10,0x00,0x00,0x00, +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00, +0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, +0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, +0x00,0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00 +}; + +/*卡纸002*/ +static unsigned char f_paperjam002[] = { +0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x44,0x44,0x44,0x44,0x44,0x44,0x40,0x40,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x02,0x04,0x08,0x10,0x00,0x00,0x00, +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00, +0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, +0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, +0x00,0x70,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00 +}; + +/*卡纸003*/ +static unsigned char f_paperjam003[] = { +0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x44,0x44,0x44,0x44,0x44,0x44,0x40,0x40,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x02,0x04,0x08,0x10,0x00,0x00,0x00, +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00, +0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, +0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, +0x00,0x30,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x18,0x20,0x21,0x21,0x22,0x1C,0x00 +}; + +/*搓纸失败*/ +static unsigned char f_feederror[] = { +0x10,0x10,0x10,0xFF,0x10,0x90,0x88,0xA9,0xAE,0xF8,0xA8,0xAC,0xAB,0x88,0x80,0x00, +0x04,0x44,0x82,0x7F,0x21,0x10,0x48,0x46,0x45,0x44,0x7C,0x44,0x44,0x44,0x40,0x00, +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00, +0x00,0x40,0x30,0x1E,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00, +0x81,0x81,0x41,0x21,0x11,0x0D,0x03,0x01,0x03,0x0D,0x11,0x21,0x41,0x81,0x81,0x00, +0x00,0xFE,0x02,0xFA,0x02,0xFE,0x40,0x20,0xD8,0x17,0x10,0x10,0xF0,0x10,0x10,0x00, +0x80,0x47,0x30,0x0F,0x10,0x67,0x80,0x40,0x21,0x16,0x08,0x16,0x21,0x40,0x80,0x00 +}; + +/*取图超时*/ +static unsigned char f_aqrimgtimeout[] = { +0x02,0x02,0xFE,0x92,0x92,0x92,0xFE,0x02,0x06,0xFC,0x04,0x04,0x04,0xFC,0x00,0x00, +0x08,0x18,0x0F,0x08,0x08,0x04,0xFF,0x04,0x84,0x40,0x27,0x18,0x27,0x40,0x80,0x00, +0x00,0xFE,0x02,0x42,0x22,0x32,0x5E,0x92,0x52,0x32,0x12,0x02,0x02,0xFE,0x00,0x00, +0x00,0xFF,0x42,0x42,0x42,0x51,0x55,0x64,0x69,0x41,0x42,0x42,0x42,0xFF,0x00,0x00, +0x40,0x48,0x48,0x48,0xFF,0x48,0x48,0x42,0xA2,0x9E,0x82,0xA2,0xC2,0xBE,0x00,0x00, +0x80,0x60,0x1F,0x20,0x7F,0x44,0x44,0x40,0x4F,0x48,0x48,0x48,0x48,0x4F,0x40,0x00, +0x00,0xFC,0x84,0x84,0x84,0xFC,0x00,0x10,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x00, +0x00,0x3F,0x10,0x10,0x10,0x3F,0x00,0x00,0x01,0x06,0x40,0x80,0x7F,0x00,0x00,0x00 +}; + +/*分纸强度*/ +static unsigned char f_pollpaperintensity[] = { +0x80,0x40,0x20,0x90,0x88,0x86,0x80,0x80,0x80,0x83,0x8C,0x10,0x20,0x40,0x80,0x00, +0x00,0x80,0x40,0x20,0x18,0x07,0x00,0x40,0x80,0x40,0x3F,0x00,0x00,0x00,0x00,0x00, +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00, +0x02,0xE2,0x22,0x22,0x3E,0x00,0x80,0x9E,0x92,0x92,0xF2,0x92,0x92,0x9E,0x80,0x00, +0x00,0x43,0x82,0x42,0x3E,0x40,0x47,0x44,0x44,0x44,0x7F,0x44,0x44,0x54,0xE7,0x00, +0x00,0x00,0xFC,0x24,0x24,0x24,0xFC,0x25,0x26,0x24,0xFC,0x24,0x24,0x24,0x04,0x00, +0x40,0x30,0x8F,0x80,0x84,0x4C,0x55,0x25,0x25,0x25,0x55,0x4C,0x80,0x80,0x80,0x00, +}; + +/*高*/ +static unsigned char f_intensityHigh[] = { +0x04,0x04,0x04,0x04,0xF4,0x94,0x95,0x96,0x94,0x94,0xF4,0x04,0x04,0x04,0x04,0x00, +0x00,0xFE,0x02,0x02,0x7A,0x4A,0x4A,0x4A,0x4A,0x4A,0x7A,0x02,0x82,0xFE,0x00,0x00 +}; + +/*中*/ +static unsigned char f_intensityMid[] = { +0x00,0x00,0xF0,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,0xF0,0x00,0x00,0x00, +0x00,0x00,0x0F,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x0F,0x00,0x00,0x00 +}; + +/*弱*/ +static unsigned char f_intensityLow[] = { +0x00,0xF2,0x92,0x92,0x92,0x92,0x9E,0x00,0xF2,0x92,0x92,0x92,0x92,0x9E,0x00,0x00, +0x00,0x10,0x11,0x4A,0x88,0x44,0x3F,0x00,0x10,0x11,0x4A,0x88,0x44,0x3F,0x00,0x00 +}; +/*低*/ +static unsigned char f_traypositionLow[] = { +0x00,0x80,0x60,0xF8,0x07,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x01,0x00,0x00,0xFF,0x00,0x00,0xFF,0x40,0x20,0x00,0x41,0x8E,0x30,0x40,0xF8,0x00 +}; +/*张*/ +static unsigned char f_page[] = { +0x02,0xE2,0x22,0x22,0x3E,0x80,0x80,0xFF,0x80,0xA0,0x90,0x88,0x86,0x80,0x80,0x00, +0x00,0x43,0x82,0x42,0x3E,0x00,0x00,0xFF,0x40,0x21,0x06,0x08,0x10,0x20,0x40,0x00 +}; + +/*扫描*/ +static unsigned char f_scan[] = { +0x10,0x10,0x10,0xFF,0x10,0x90,0x04,0x84,0x84,0x84,0x84,0x84,0x84,0xFC,0x00,0x00, +0x04,0x44,0x82,0x7F,0x01,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7F,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x10,0x10,0xFF,0x10,0x90,0x04,0xC4,0x5F,0x44,0xC4,0x44,0x5F,0xC4,0x04,0x00, +0x04,0x44,0x82,0x7F,0x01,0x00,0x00,0xFF,0x44,0x44,0x7F,0x44,0x44,0xFF,0x00,0x00 +}; + +/*返回*/ +static unsigned char f_back[] = { +0x40,0x40,0x42,0xCE,0xCC,0x00,0xFC,0xFC,0xA4,0xA4,0x26,0x22,0xA3,0xE3,0x62,0x00, +0x00,0x40,0x60,0x3F,0x3F,0x78,0x5F,0x57,0x58,0x4D,0x47,0x47,0x4D,0x58,0x50,0x40, +0x00,0x00,0xFE,0xFE,0x02,0xF2,0xF2,0x12,0x12,0xF2,0xF2,0x02,0xFE,0xFE,0x00,0x00, +0x00,0x00,0x7F,0x7F,0x20,0x27,0x27,0x24,0x24,0x27,0x27,0x20,0x7F,0x7F,0x00,0x00 +}; + +/*确认*/ +static unsigned char f_confirm[] = { +0x04,0x84,0xE4,0x5C,0x44,0xC4,0x20,0x10,0xE8,0x27,0x24,0xE4,0x34,0x2C,0xE0,0x00, +0x02,0x01,0x7F,0x10,0x10,0x3F,0x80,0x60,0x1F,0x09,0x09,0x3F,0x49,0x89,0x7F,0x00, +0x40,0x40,0x42,0xCC,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x3F,0x90,0x48,0x20,0x18,0x07,0x00,0x07,0x18,0x20,0x40,0x80,0x00 +}; + +/*开*/ +static unsigned char f_opened[] = { +0x80,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x80,0x00, +0x00,0x80,0x40,0x30,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00 +}; + +/*关*/ +static unsigned char f_closed[] = { +0x80,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x80,0x00, +0x00,0x80,0x40,0x30,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00 +}; + +/*无纸*/ +static unsigned char f_nopaper[] = { +0x00,0x40,0x42,0x42,0x42,0xC2,0x7E,0x42,0xC2,0x42,0x42,0x42,0x40,0x40,0x00,0x00, +0x80,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x3F,0x40,0x40,0x40,0x40,0x70,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x84,0x84,0x84,0xFE,0x82,0x83,0x82,0x80,0x00, +0x22,0x67,0x22,0x12,0x12,0x00,0xFF,0x40,0x20,0x00,0x01,0x0E,0x30,0x40,0xF8,0x00 +}; + +/*休眠模式*/ +static unsigned char f_sleepmode[] = { +0x00,0x80,0x60,0xF8,0x07,0x10,0x10,0x10,0xD0,0xFF,0xD0,0x10,0x10,0x10,0x10,0x00, +0x01,0x00,0x00,0xFF,0x10,0x08,0x04,0x03,0x00,0xFF,0x00,0x03,0x04,0x08,0x10,0x00, +0x00,0xFC,0x24,0x24,0x24,0xFC,0x00,0xFE,0x22,0x22,0xE2,0x22,0x22,0x3E,0x00,0x00, +0x00,0x3F,0x11,0x11,0x11,0x3F,0x00,0xFF,0x41,0x21,0x07,0x19,0x21,0x41,0xF1,0x00, +0x10,0x10,0xD0,0xFF,0x90,0x14,0xE4,0xAF,0xA4,0xA4,0xA4,0xAF,0xE4,0x04,0x00,0x00, +0x04,0x03,0x00,0xFF,0x00,0x89,0x4B,0x2A,0x1A,0x0E,0x1A,0x2A,0x4B,0x88,0x80,0x00, +0x10,0x10,0x90,0x90,0x90,0x90,0x90,0x10,0x10,0xFF,0x10,0x10,0x11,0x16,0x10,0x00, +0x00,0x20,0x60,0x20,0x3F,0x10,0x10,0x10,0x00,0x03,0x0C,0x10,0x20,0x40,0xF8,0x00 +}; + + +/*三十分钟*/ +static unsigned char f_30min[] = { +0x00,0x04,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x04,0x00,0x00, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x80,0x40,0x20,0x90,0x88,0x86,0x80,0x80,0x80,0x83,0x8C,0x10,0x20,0x40,0x80,0x00, +0x00,0x80,0x40,0x20,0x18,0x07,0x00,0x40,0x80,0x40,0x3F,0x00,0x00,0x00,0x00,0x00, +0x20,0x10,0x2C,0xE7,0x24,0x24,0x00,0xF0,0x10,0x10,0xFF,0x10,0x10,0xF0,0x00,0x00, +0x01,0x01,0x01,0x7F,0x21,0x11,0x00,0x07,0x02,0x02,0xFF,0x02,0x02,0x07,0x00,0x00, +}; + +/*一小时*/ +static unsigned char f_1hour[] = { +0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x20,0x40,0x80,0x00,0x00, +0x08,0x04,0x03,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x01,0x0E,0x00, +0x00,0xFC,0x84,0x84,0x84,0xFC,0x00,0x10,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x00, +0x00,0x3F,0x10,0x10,0x10,0x3F,0x00,0x00,0x01,0x06,0x40,0x80,0x7F,0x00,0x00,0x00 +}; + +/*二小时*/ +static unsigned char f_2hour[] = { +0x02,0xE2,0x22,0x22,0x22,0xFE,0x22,0x22,0x22,0xFE,0x22,0x22,0x22,0xE2,0x02,0x00, +0x00,0xFF,0x00,0x08,0x06,0x01,0x16,0x08,0x06,0x01,0x02,0x4C,0x80,0x7F,0x00,0x00, +0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x20,0x40,0x80,0x00,0x00, +0x08,0x04,0x03,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x01,0x0E,0x00, +0x00,0xFC,0x84,0x84,0x84,0xFC,0x00,0x10,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x00, +0x00,0x3F,0x10,0x10,0x10,0x3F,0x00,0x00,0x01,0x06,0x40,0x80,0x7F,0x00,0x00,0x00 +}; + +/*不休眠*/ +static unsigned char f_never[] = { +0x00,0x02,0x02,0x02,0x02,0x82,0x42,0xF2,0x0E,0x42,0x82,0x02,0x02,0x02,0x00,0x00, +0x10,0x08,0x04,0x02,0x01,0x00,0x00,0xFF,0x00,0x00,0x00,0x01,0x02,0x0C,0x00,0x00, +0x00,0x80,0x60,0xF8,0x07,0x10,0x10,0x10,0xD0,0xFF,0xD0,0x10,0x10,0x10,0x10,0x00, +0x01,0x00,0x00,0xFF,0x10,0x08,0x04,0x03,0x00,0xFF,0x00,0x03,0x04,0x08,0x10,0x00, +0x00,0xFC,0x24,0x24,0x24,0xFC,0x00,0xFE,0x22,0x22,0xE2,0x22,0x22,0x3E,0x00,0x00, +0x00,0x3F,0x11,0x11,0x11,0x3F,0x00,0xFF,0x41,0x21,0x07,0x19,0x21,0x41,0xF1,0x00 +}; + + +/*返回*/ +static unsigned char f_return[] = { +0x40,0x40,0x42,0xCC,0x00,0x00,0xFC,0x24,0xA4,0x24,0x22,0x22,0xA3,0x62,0x00,0x00, +0x00,0x40,0x20,0x1F,0x20,0x58,0x47,0x50,0x48,0x45,0x42,0x45,0x48,0x50,0x40,0x00, +0x00,0x00,0xFE,0x02,0x02,0xF2,0x12,0x12,0x12,0xF2,0x02,0x02,0xFE,0x00,0x00,0x00, +0x00,0x00,0x7F,0x20,0x20,0x27,0x24,0x24,0x24,0x27,0x20,0x20,0x7F,0x00,0x00,0x00 +}; + +/*关机*/ +static unsigned char f_powerof[] = { +0x00,0x00,0x10,0x11,0x16,0x10,0x10,0xF0,0x10,0x10,0x14,0x13,0x10,0x00,0x00,0x00, +0x81,0x81,0x41,0x41,0x21,0x11,0x0D,0x03,0x0D,0x11,0x21,0x41,0x41,0x81,0x81,0x00, +0x10,0x10,0xD0,0xFF,0x90,0x10,0x00,0xFE,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00, +0x04,0x03,0x00,0xFF,0x00,0x83,0x60,0x1F,0x00,0x00,0x00,0x3F,0x40,0x40,0x78,0x00 +}; + +/*托盘位置*/ +static unsigned char f_trayposition[] = { +0x10,0x10,0x10,0xFF,0x10,0x90,0x04,0x04,0x04,0xFC,0x82,0x82,0x83,0x82,0x80,0x00, +0x04,0x44,0x82,0x7F,0x01,0x00,0x01,0x01,0x01,0x3F,0x40,0x40,0x40,0x40,0x78,0x00, +0x20,0x20,0x20,0xFC,0x24,0x26,0xA5,0x2C,0x34,0x24,0x24,0xFC,0x20,0x20,0x20,0x00, +0x40,0x42,0x7D,0x44,0x44,0x7C,0x44,0x45,0x44,0x7D,0x46,0x45,0x7C,0x40,0x40,0x00, +0x00,0x80,0x60,0xF8,0x07,0x10,0x90,0x10,0x11,0x16,0x10,0x10,0xD0,0x10,0x00,0x00, +0x01,0x00,0x00,0xFF,0x40,0x40,0x41,0x5E,0x40,0x40,0x70,0x4E,0x41,0x40,0x40,0x00, +0x00,0x17,0x15,0xD5,0x55,0x57,0x55,0x7D,0x55,0x57,0x55,0xD5,0x15,0x17,0x00,0x00, +0x40,0x40,0x40,0x7F,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x7F,0x40,0x40,0x40,0x00 +}; + + +/*设备已锁定*/ +static unsigned char f_deviceLock[] = { +0x40,0x40,0x42,0xCC,0x00,0x40,0xA0,0x9E,0x82,0x82,0x82,0x9E,0xA0,0x20,0x20,0x00, +0x00,0x00,0x00,0x3F,0x90,0x88,0x40,0x43,0x2C,0x10,0x28,0x46,0x41,0x80,0x80,0x00,/*"设",0*/ +0x80,0x90,0x90,0x48,0x4C,0x57,0x24,0x24,0x24,0x54,0x4C,0x44,0x80,0x80,0x80,0x00, +0x00,0x00,0x00,0xFF,0x49,0x49,0x49,0x7F,0x49,0x49,0x49,0xFF,0x00,0x00,0x00,0x00,/*"备",1*/ +0x00,0x00,0xE2,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,0x00,0x00,0x00, +0x00,0x00,0x3F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x78,0x00,0x00,/*"已",2*/ +0x20,0x10,0x2C,0xE7,0x24,0x24,0x00,0xE2,0x2C,0x20,0xBF,0x20,0x28,0xE6,0x00,0x00, +0x01,0x01,0x01,0x7F,0x21,0x11,0x80,0x4F,0x20,0x10,0x0F,0x10,0x20,0x4F,0x80,0x00,/*"锁",3*/ +0x10,0x0C,0x44,0x44,0x44,0x44,0x45,0xC6,0x44,0x44,0x44,0x44,0x44,0x14,0x0C,0x00, +0x80,0x40,0x20,0x1E,0x20,0x40,0x40,0x7F,0x44,0x44,0x44,0x44,0x44,0x40,0x40,0x00,/*"定",4*/ +}; diff --git a/device/gxx-linux/display/LCDDisplay.cpp b/device/gxx-linux/display/LCDDisplay.cpp new file mode 100644 index 0000000..7ddfcc9 --- /dev/null +++ b/device/gxx-linux/display/LCDDisplay.cpp @@ -0,0 +1,152 @@ +#include "LCDDisplay.h" +#include "Lcd.h" +#include +#include +#include +#include "stringex.hpp" + +using namespace std; + +LCDDisplay::LCDDisplay() +{ + lcd.reset(new Lcd()); + lcd->Lcd_Initial_Lcd(false); + // lcd->Lcd_Clear_screen(); + // lcd->Lcd_Display_Graphic_16x16(map_Display[DisType::Dis_Init].page, map_Display[DisType::Dis_Init].col, map_Display[DisType::Dis_Init].str.data(),map_Display[DisType::Dis_Init].str.size()/32); +} + +LCDDisplay::~LCDDisplay() +{ + lcd->Lcd_Clear_screen(); + lcd.reset(); +} + +void LCDDisplay::DisplayState(DisType ds, unsigned int pagenum,ClearScreen clearscree) +{ + if(clearscree == ClearScreen::All) + lcd->Lcd_Clear_screen(); + if(clearscree == ClearScreen::TOP) + lcd->Lcd_Clear_Half_Screen(true); + if(clearscree == ClearScreen::BOT) + lcd->Lcd_Clear_Half_Screen(false); + if (map_Display.count(ds) > 0) + { + m_status = ds; + StopWatch sw; + auto dsinfo = map_Display[ds]; + if (ds == DisType::Dis_Welcome)//show logo + { + lcd->Lcd_Display_Graphic_128x64(dsinfo.page, dsinfo.col, dsinfo.str.data()); + } + else + { + lcd->Lcd_Display_Graphic_16x16(dsinfo.page, dsinfo.col, dsinfo.str.data(), dsinfo.str.size() / 32); + //if (ds == DisType::Dis_Scan || ds == DisType::Dis_Set_Count) //扫描或者计数 更新下半部分内容 + //{ + //lcd->Lcd_Clear_Half_Screen(false); + //lcd->Lcd_Display_String_8x16(3, 96, "0"); + //lcd->Lcd_Display_Graphic_16x16(map_Display[DisType::Dis_Scan_Page].page, map_Display[DisType::Dis_Scan_Page].col, map_Display[DisType::Dis_Scan_Page].str.data(), map_Display[DisType::Dis_Scan_Page].str.size() / 32); + //} + } + + switch (ds) + { + case DisType::Dis_Count_Page: + case DisType::Dis_Scan_Page: + { + //std::string val = std::to_string(pagenum); + //auto offsetdot = bitnum(pagenum) - 1; + std::string val = string_format("%04d",pagenum); + int offsetdot = val.length(); + //printf("\n val = %s lenght = %d",val.c_str(),val.size()); + lcd->Lcd_Display_String_8x16(3, 112 - offsetdot * 8, val.c_str()); //8 -> 一个数字所占点个数宽度 + lcd->Lcd_Display_Graphic_16x16(map_Display[DisType::Dis_Scan_Page].page, map_Display[DisType::Dis_Scan_Page].col, map_Display[DisType::Dis_Scan_Page].str.data(), map_Display[DisType::Dis_Scan_Page].str.size() / 32); + break; + } + case DisType::Dis_Err_JamIn: + { + if(pagenum == 1) + lcd->Lcd_Display_String_8x16(3, 56, "P a 1 0 1"); //8 -> 一个数字所占点个数宽度 + else if(pagenum == 2) + lcd->Lcd_Display_String_8x16(3, 56, "P a 1 0 2"); + else if(pagenum == 3) + lcd->Lcd_Display_String_8x16(3, 56, "P a 1 0 3"); + break; + } + case DisType::Dis_Err_AqrImgTimeout: + lcd->Lcd_Display_String_8x16(3, 56, "G p 0 0 1"); + break; + case DisType::Dis_Err_CoverOpen: + lcd->Lcd_Display_String_8x16(3, 56, "C o 0 0 1"); + break; + case DisType::Dis_Err_PaperScrew: + lcd->Lcd_Display_String_8x16(3, 56, "S K 0 0 1"); + break; + case DisType::Dis_Err_DoubleFeed: + lcd->Lcd_Display_String_8x16(3, 56, "D b 0 0 1"); + break; + case DisType::Dis_Err_NoPaper: + lcd->Lcd_Display_String_8x16(3, 56, "N o 0 0 1"); + break; + case DisType::Dis_Err_Stable: + lcd->Lcd_Display_String_8x16(3, 56, "S T 0 0 1"); + break; + case DisType::Dis_Err_FeedError: + lcd->Lcd_Display_String_8x16(3, 56, "P f 0 0 1"); + break; + case DisType::Dis_Err_DogEar: + lcd->Lcd_Display_String_8x16(3, 56, "Z J 0 0 1"); + break; + case DisType::Dis_Err_Size: + lcd->Lcd_Display_String_8x16(3, 56, "C C 0 0 1"); + break; + default: + break; + } + } + else + { + switch (ds){ + case DisType::Dis_Set_SleepMode_5M: + lcd->Lcd_Display_String_8x16(3, 112, "5M"); + break; + case DisType::Dis_Set_SleepMode_10M: + lcd->Lcd_Display_String_8x16(3, 104, "10M"); + break; + case DisType::Dis_Set_SleepMode_20M: + lcd->Lcd_Display_String_8x16(3, 104, "20M"); + break; + case DisType::Dis_Set_SleepMode_30M: + lcd->Lcd_Display_String_8x16(3, 104, "30M"); + break; + case DisType::Dis_Set_SleepMode_1H: + lcd->Lcd_Display_String_8x16(3, 112, "1H"); + break; + case DisType::Dis_Set_SleepMode_2H: + lcd->Lcd_Display_String_8x16(3, 112, "2H"); + break; + case DisType::Dis_Set_SleepMode_4H: + lcd->Lcd_Display_String_8x16(3, 112, "4H"); + break; + default: + m_status= DisType::Dis_Unkown; + break; + } + } +} + +int LCDDisplay::bitnum(unsigned int num) +{ + int count = 0; + do + { + num = num / 10; + count++; + } while (num > 0); + return count; +} + +DisType LCDDisplay::GetCurrentStatus() const +{ + return m_status; +} \ No newline at end of file diff --git a/device/gxx-linux/display/LCDDisplay.h b/device/gxx-linux/display/LCDDisplay.h new file mode 100644 index 0000000..e5d625b --- /dev/null +++ b/device/gxx-linux/display/LCDDisplay.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include "Displaydef.h" + +class Lcd; + +class LCDDisplay +{ +private: + /* data */ +public: + LCDDisplay(/* args */); + ~LCDDisplay(); + void DisplayState(DisType ds,unsigned int pagenum,ClearScreen clearscree); + DisType GetCurrentStatus() const; +private: + int bitnum(unsigned int num); +private: + std::shared_ptr lcd; + DisType m_status; +}; diff --git a/device/gxx-linux/display/Lcd.cpp b/device/gxx-linux/display/Lcd.cpp new file mode 100644 index 0000000..4e74a9b --- /dev/null +++ b/device/gxx-linux/display/Lcd.cpp @@ -0,0 +1,780 @@ +#include "Lcd.h" +#include +#include +#include +#include "DevUtil.h" + +using namespace std; + +#define IOEXPORTPATH "/sys/class/gpio/export" +#define DELAY_US(t) this_thread::sleep_for(chrono::microseconds((t))) +#define DELAY_MS(t) this_thread::sleep_for(chrono::milliseconds((t))) + +static unsigned char ascii_table_8x16[95][16] = { + + /*-- 文字: --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: ! --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00, + + /*-- 文字: " --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: # --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00, 0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00, + + /*-- 文字: $ --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00, 0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00, + + /*-- 文字: % --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00, 0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00, + + /*-- 文字: & --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00, 0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10, + + /*-- 文字: ' --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: ( --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00, + + /*-- 文字: ) --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00, + + /*-- 文字: * --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00, 0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00, + + /*-- 文字: + --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00, + + /*-- 文字: , --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: - --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + + /*-- 文字: . --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: / --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04, 0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, + + /*-- 文字: 0 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00, + + /*-- 文字: 1 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, + + /*-- 文字: 2 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00, + + /*-- 文字: 3 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00, 0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, + + /*-- 文字: 4 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00, + + /*-- 文字: 5 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00, 0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00, + + /*-- 文字: 6 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00, 0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, + + /*-- 文字: 7 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: 8 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00, + + /*-- 文字: 9 --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00, + + /*-- 文字: : --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, + + /*-- 文字: ; --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: < --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, + + /*-- 文字: = --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, + + /*-- 文字: > --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, + + /*-- 文字: ? --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00, + + /*-- 文字: @ --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00, 0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00, + + /*-- 文字: A --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20, + + /*-- 文字: B --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, + + /*-- 文字: C --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, + + /*-- 文字: D --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, + + /*-- 文字: E --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00, + + /*-- 文字: F --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, + + /*-- 文字: G --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00, + + /*-- 文字: H --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20, + + /*-- 文字: I --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, + + /*-- 文字: J --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00, + + /*-- 文字: K --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00, 0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00, + + /*-- 文字: L --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00, + + /*-- 文字: M --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00, 0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00, + + /*-- 文字: N --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00, + + /*-- 文字: O --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, + + /*-- 文字: P --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00, + + /*-- 文字: Q --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00, + + /*-- 文字: R --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20, + + /*-- 文字: S --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00, + + /*-- 文字: T --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, + + /*-- 文字: U --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, + + /*-- 文字: V --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00, + + /*-- 文字: W --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00, 0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00, + + /*-- 文字: X --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08, 0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20, + + /*-- 文字: Y --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, + + /*-- 文字: Z --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00, + + /*-- 文字: [ --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00, + + /*-- 文字: \ --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00, + + /*-- 文字: ] --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00, + + /*-- 文字: ^ --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: _ --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + + /*-- 文字: ` --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: a --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20, + + /*-- 文字: b --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, + + /*-- 文字: c --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00, + + /*-- 文字: d --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20, + + /*-- 文字: e --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00, + + /*-- 文字: f --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, + + /*-- 文字: g --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00, + + /*-- 文字: h --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, + + /*-- 文字: i --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, + + /*-- 文字: j --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, + + /*-- 文字: k --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00, + + /*-- 文字: l --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, + + /*-- 文字: m --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F, + + /*-- 文字: n --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, + + /*-- 文字: o --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, + + /*-- 文字: p --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00, + + /*-- 文字: q --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80, + + /*-- 文字: r --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00, + + /*-- 文字: s --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00, + + /*-- 文字: t --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00, + + /*-- 文字: u --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20, + + /*-- 文字: v --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00, + + /*-- 文字: w --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, 0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00, + + /*-- 文字: x --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00, + + /*-- 文字: y --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00, + + /*-- 文字: z --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00, + + /*-- 文字: { --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40, + + /*-- 文字: | --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + + /*-- 文字: } --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, + + /*-- 文字: ~ --*/ + /*-- Comic Sans MS12; 此字体下对应的点阵为:宽x高=8x16 --*/ + 0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +}; + +static unsigned char ascii_table_5x8[95][5] = { + /*全体ASCII 列表:5x8点阵*/ + 0x00, 0x00, 0x00, 0x00, 0x00, //space + 0x00, 0x00, 0x4f, 0x00, 0x00, //! + 0x00, 0x07, 0x00, 0x07, 0x00, //" + 0x14, 0x7f, 0x14, 0x7f, 0x14, //# + 0x24, 0x2a, 0x7f, 0x2a, 0x12, //$ + 0x23, 0x13, 0x08, 0x64, 0x62, //% + 0x36, 0x49, 0x55, 0x22, 0x50, //& + 0x00, 0x05, 0x07, 0x00, 0x00, //] + 0x00, 0x1c, 0x22, 0x41, 0x00, //( + 0x00, 0x41, 0x22, 0x1c, 0x00, //) + 0x14, 0x08, 0x3e, 0x08, 0x14, //* + 0x08, 0x08, 0x3e, 0x08, 0x08, //+ + 0x00, 0x50, 0x30, 0x00, 0x00, //, + 0x08, 0x08, 0x08, 0x08, 0x08, //- + 0x00, 0x60, 0x60, 0x00, 0x00, //. + 0x20, 0x10, 0x08, 0x04, 0x02, /// + 0x3e, 0x51, 0x49, 0x45, 0x3e, //0 + 0x00, 0x42, 0x7f, 0x40, 0x00, //1 + 0x42, 0x61, 0x51, 0x49, 0x46, //2 + 0x21, 0x41, 0x45, 0x4b, 0x31, //3 + 0x18, 0x14, 0x12, 0x7f, 0x10, //4 + 0x27, 0x45, 0x45, 0x45, 0x39, //5 + 0x3c, 0x4a, 0x49, 0x49, 0x30, //6 + 0x01, 0x71, 0x09, 0x05, 0x03, //7 + 0x36, 0x49, 0x49, 0x49, 0x36, //8 + 0x06, 0x49, 0x49, 0x29, 0x1e, //9 + 0x00, 0x36, 0x36, 0x00, 0x00, //: + 0x00, 0x56, 0x36, 0x00, 0x00, //; + 0x08, 0x14, 0x22, 0x41, 0x00, //< + 0x14, 0x14, 0x14, 0x14, 0x14, //= + 0x00, 0x41, 0x22, 0x14, 0x08, //> + 0x02, 0x01, 0x51, 0x09, 0x06, //? + 0x32, 0x49, 0x79, 0x41, 0x3e, //@ + 0x7e, 0x11, 0x11, 0x11, 0x7e, //A + 0x7f, 0x49, 0x49, 0x49, 0x36, //B + 0x3e, 0x41, 0x41, 0x41, 0x22, //C + 0x7f, 0x41, 0x41, 0x22, 0x1c, //D + 0x7f, 0x49, 0x49, 0x49, 0x41, //E + 0x7f, 0x09, 0x09, 0x09, 0x01, //F + 0x3e, 0x41, 0x49, 0x49, 0x7a, //G + 0x7f, 0x08, 0x08, 0x08, 0x7f, //H + 0x00, 0x41, 0x7f, 0x41, 0x00, //I + 0x20, 0x40, 0x41, 0x3f, 0x01, //J + 0x7f, 0x08, 0x14, 0x22, 0x41, //K + 0x7f, 0x40, 0x40, 0x40, 0x40, //L + 0x7f, 0x02, 0x0c, 0x02, 0x7f, //M + 0x7f, 0x04, 0x08, 0x10, 0x7f, //N + 0x3e, 0x41, 0x41, 0x41, 0x3e, //O + 0x7f, 0x09, 0x09, 0x09, 0x06, //P + 0x3e, 0x41, 0x51, 0x21, 0x5e, //Q + 0x7f, 0x09, 0x19, 0x29, 0x46, //R + 0x46, 0x49, 0x49, 0x49, 0x31, //S + 0x01, 0x01, 0x7f, 0x01, 0x01, //T + 0x3f, 0x40, 0x40, 0x40, 0x3f, //U + 0x1f, 0x20, 0x40, 0x20, 0x1f, //V + 0x3f, 0x40, 0x38, 0x40, 0x3f, //W + 0x63, 0x14, 0x08, 0x14, 0x63, //X + 0x07, 0x08, 0x70, 0x08, 0x07, //Y + 0x61, 0x51, 0x49, 0x45, 0x43, //Z + 0x00, 0x7f, 0x41, 0x41, 0x00, //[ + 0x02, 0x04, 0x08, 0x10, 0x20, //\ +0x00,0x41,0x41,0x7f,0x00,//] + 0x04, 0x02, 0x01, 0x02, 0x04, //^ + 0x40, 0x40, 0x40, 0x40, 0x40, //_ + 0x01, 0x02, 0x04, 0x00, 0x00, //` + 0x20, 0x54, 0x54, 0x54, 0x78, //a + 0x7f, 0x48, 0x48, 0x48, 0x30, //b + 0x38, 0x44, 0x44, 0x44, 0x44, //c + 0x30, 0x48, 0x48, 0x48, 0x7f, //d + 0x38, 0x54, 0x54, 0x54, 0x58, //e + 0x00, 0x08, 0x7e, 0x09, 0x02, //f + 0x48, 0x54, 0x54, 0x54, 0x3c, //g + 0x7f, 0x08, 0x08, 0x08, 0x70, //h + 0x00, 0x00, 0x7a, 0x00, 0x00, //i + 0x20, 0x40, 0x40, 0x3d, 0x00, //j + 0x7f, 0x20, 0x28, 0x44, 0x00, //k + 0x00, 0x41, 0x7f, 0x40, 0x00, //l + 0x7c, 0x04, 0x38, 0x04, 0x7c, //m + 0x7c, 0x08, 0x04, 0x04, 0x78, //n + 0x38, 0x44, 0x44, 0x44, 0x38, //o + 0x7c, 0x14, 0x14, 0x14, 0x08, //p + 0x08, 0x14, 0x14, 0x14, 0x7c, //q + 0x7c, 0x08, 0x04, 0x04, 0x08, //r + 0x48, 0x54, 0x54, 0x54, 0x24, //s + 0x04, 0x04, 0x3f, 0x44, 0x24, //t + 0x3c, 0x40, 0x40, 0x40, 0x3c, //u + 0x1c, 0x20, 0x40, 0x20, 0x1c, //v + 0x3c, 0x40, 0x30, 0x40, 0x3c, //w + 0x44, 0x28, 0x10, 0x28, 0x44, //x + 0x04, 0x48, 0x30, 0x08, 0x04, //y + 0x44, 0x64, 0x54, 0x4c, 0x44, //z + 0x08, 0x36, 0x41, 0x41, 0x00, //{ + 0x00, 0x00, 0x77, 0x00, 0x00, //| + 0x00, 0x41, 0x41, 0x36, 0x08, //} + 0x04, 0x02, 0x02, 0x02, 0x01, //~ +}; + + +Lcd::Lcd() : spi_sck(51), spi_sda(72), spi_cs(154), spi_reset(150), spi_rs(156),COM_BOOT0(153) + +{ + printf("Lcd()\n"); + write_dev(IOEXPORTPATH,51); + write_dev(IOEXPORTPATH,72); + write_dev(IOEXPORTPATH,154); + write_dev(IOEXPORTPATH,150); + write_dev(IOEXPORTPATH,156); + write_dev(IOEXPORTPATH,153); + + COM_BOOT0.setDirection(Gpio::out); + spi_sck.setDirection(Gpio::out); + spi_sda.setDirection(Gpio::out); + spi_cs.setDirection(Gpio::out); + spi_reset.setDirection(Gpio::out); + spi_rs.setDirection(Gpio::out); + + COM_BOOT0.setValue(Gpio::Low); + spi_sck.setValue(Gpio::High); + spi_sda.setValue(Gpio::High); + spi_cs.setValue(Gpio::High); + spi_reset.setValue(Gpio::High); + spi_rs.setValue(Gpio::High); +} + +/*=======写指令========*/ +void Lcd::Lcd_Transfer_Command(int data1) +{ + spi_cs.setValue(Gpio::Low); + spi_rs.setValue(Gpio::Low); + for (int i = 0; i < 8; i++) + { + spi_sck.setValue(Gpio::Low); + + if (data1 & 0x80) + spi_sda.setValue(Gpio::High); + else + spi_sda.setValue(Gpio::Low); + spi_sck.setValue(Gpio::High); + data1 = data1 <<= 1; + } + spi_cs.setValue(Gpio::High); +} + +/*--------写数据------------*/ +void Lcd::Lcd_Transfer_data(int data1) +{ + spi_cs.setValue(Gpio::Low); + spi_rs.setValue(Gpio::High); + for (int i = 0; i < 8; i++) + { + spi_sck.setValue(Gpio::Low); + if (data1 & 0x80) + spi_sda.setValue(Gpio::High); + else + spi_sda.setValue(Gpio::Low); + spi_sck.setValue(Gpio::High); + data1 = data1 <<= 1; + } + spi_cs.setValue(Gpio::High); +} + +/*LCD模块初始化*/ +void Lcd::Lcd_Initial_Lcd(bool biglcd) +{ + spi_cs.setValue(Gpio::Low); + spi_reset.setValue(Gpio::Low); /*低电平复位*/ + DELAY_MS(20); + spi_reset.setValue(Gpio::High); /*复位完毕*/ + DELAY_MS(20); + Lcd_Transfer_Command(0xe2); /*软复位*/ + DELAY_MS(50); + Lcd_Transfer_Command(0x2c); /*升压步聚1*/ + DELAY_MS(50); + Lcd_Transfer_Command(0x2e); /*升压步聚2*/ + DELAY_MS(50); + Lcd_Transfer_Command(0x2f); /*升压步聚3*/ + DELAY_MS(50); + Lcd_Transfer_Command(biglcd?0x21:0x24); /*0X24粗调对比度,可设置范围0x20~0x27*/ + Lcd_Transfer_Command(0x81); /*微调对比度*/ + Lcd_Transfer_Command(biglcd?0x28:0x15); /*45微调对比度的值,可设置范围0x00~0x3f 1f*/ // 0~63 + Lcd_Transfer_Command(0xa2); /*1/9偏压比(bias)0xa2 ,1/7bias 0xa3*/ + Lcd_Transfer_Command(0xc8); /*行扫描顺序:从上到下*/ //原 c0 字体倒置 CF ///////////////////////////////////////////////////////////// + Lcd_Transfer_Command(0xa0); /*列扫描顺序:从左到右*/ //原 a1 字体倒置 A0 //////////////////////////////////////////////// + Lcd_Transfer_Command(0x40); /*起始行:第一行开始*/ + Lcd_Transfer_Command(0xaf); /*开显示*/ + spi_cs.setValue(Gpio::High); +} + +void Lcd::Lcd_Address(unsigned char page, unsigned char column) +{ + spi_cs.setValue(Gpio::Low); + column = column - 1; + page = page - 1; + Lcd_Transfer_Command(0xb0 + page); //设置页地址。每页是8行。一个画面的64行被分成8个页。我们平常所说的第1页,在LCD驱动IC里是第0页,所以在这里减去1*/ + Lcd_Transfer_Command(((column >> 4) & 0x0f) + 0x10); //设置列地址的高4位 + Lcd_Transfer_Command(column & 0x0f); //设置列地址的低4位 +} + +/*全屏清屏*/ +void Lcd::Lcd_Clear_screen() +{ + unsigned char i, j; + spi_cs.setValue(Gpio::Low); + for (i = 0; i < 4; i++) + { + Lcd_Address(1 + i, 1); + for (j = 0; j < 132; j++) + { + Lcd_Transfer_data(0x00); + } + } + spi_cs.setValue(Gpio::High); +} + +//===显示测试画面:例如全显示,隔行显示,隔列显示,雪花显示===== +void Lcd::Lcd_Test_Display(unsigned char data1, unsigned char data2) +{ + int i, j; + for (j = 0; j < 8; j++) + { + spi_cs.setValue(Gpio::Low); + Lcd_Address(j + 1, 1); + for (i = 0; i < 128; i++) + { + Lcd_Transfer_data(data1); + Lcd_Transfer_data(data2); + } + } +} + +/*显示128x64点阵图像*/ +void Lcd::Lcd_Display_Graphic_128x64(unsigned char page, unsigned char column, unsigned char *dp) +{ + int i, j; + for (j = 0; j < 8; j++) + { + spi_cs.setValue(Gpio::Low); + Lcd_Address(page + j, column); + for (i = 0; i < 128; i++) + { + Lcd_Transfer_data(*dp); + dp++; + } + } +} + +/*显示32x32点阵图像、汉字、生僻字或32x32点阵的其他图标*/ +void Lcd::Lcd_Display_graphic_32x32(unsigned char page, unsigned char column, unsigned char *dp) +{ + unsigned char i, j; + spi_cs.setValue(Gpio::Low); + for (j = 0; j < 4; j++) + { + Lcd_Address(page + j, column); + for (i = 0; i < 31; i++) + { + Lcd_Transfer_data(*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + dp++; + } + } +} + +/*显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标*/ +void Lcd::Lcd_Display_Graphic_16x16_2(unsigned char reverse, unsigned char page, unsigned char column, unsigned char *dp) +{ + unsigned char i, j; + + spi_cs.setValue(Gpio::Low); + for (j = 0; j < 2; j++) + { + Lcd_Address(page + j, column); + for (i = 0; i < 16; i++) + { + if (reverse == 1) + Lcd_Transfer_data(*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + else + Lcd_Transfer_data(~*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + dp++; + } + } + spi_cs.setValue(Gpio::High); +} + +/*显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标*/ +void Lcd::Lcd_Display_Graphic_16x16(unsigned char page, unsigned char column, unsigned char *dp, unsigned int wordcount) +{ + unsigned char i, j, k; + spi_cs.setValue(Gpio::Low); + for (k = 0; k < wordcount; k++) + { + for (j = 0; j < 2; j++) + { + Lcd_Address(page + j, column + 16 * k); + for (i = 0; i < 16; i++) + { + Lcd_Transfer_data(*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + dp++; + } + } + } + spi_cs.setValue(Gpio::High); +} + +/*显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标*/ +void Lcd::Lcd_Display_Graphic_8x16(unsigned char page, unsigned char column, unsigned char *dp) +{ + unsigned char i, j; + spi_cs.setValue(Gpio::Low); + for (j = 0; j < 2; j++) + { + Lcd_Address(page + j, column); + for (i = 0; i < 8; i++) + { + Lcd_Transfer_data(*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + dp++; + } + } + spi_cs.setValue(Gpio::High); +} + +void Lcd::Lcd_Display_String_8x16(unsigned int page, unsigned int column, const char *text) +{ + unsigned int i = 0, j, k, n; + spi_cs.setValue(Gpio::Low); + while (text[i] > 0x00) + { + if ((text[i] >= 0x20) && (text[i] <= 0x7e)) + { + j = text[i] - 0x20; + for (n = 0; n < 2; n++) + { + Lcd_Address(page + n, column); + for (k = 0; k < 8; k++) + { + Lcd_Transfer_data(ascii_table_8x16[j][k + 8 * n]); /*显示5x7的ASCII字到LCD上,y为页地址,x为列地址,最后为数据*/ + } + } + i++; + column += 8; + } + else + i++; + } +} + +void Lcd::Lcd_Display_String_5x8(unsigned int page, unsigned int column, const char *text) +{ + unsigned int i = 0, j, k; + spi_cs.setValue(Gpio::Low); + while (text[i] > 0x00) + { + if ((text[i] >= 0x20) && (text[i] < 0x7e)) + { + j = text[i] - 0x20; + Lcd_Address(page, column); + for (k = 0; k < 5; k++) + { + Lcd_Transfer_data(ascii_table_5x8[j][k]); /*显示5x7的ASCII字到LCD上,y为页地址,x为列地址,最后为数据*/ + } + i++; + column += 6; + } + else + i++; + } +} + +void Lcd::Lcd_Clear_Half_Screen(bool top) +{ + int pageindex = top ? 0 : 2; + int pagemaxindex = top ? 2 : 4; + spi_cs.setValue(Gpio::Low); + for (int i = pageindex; i < pagemaxindex; i++) + { + Lcd_Address(1 + i, 1); + for (int j = 0; j < 132; j++) + { + Lcd_Transfer_data(0x00); + } + } + spi_cs.setValue(Gpio::High); +} diff --git a/device/gxx-linux/display/Lcd.h b/device/gxx-linux/display/Lcd.h new file mode 100644 index 0000000..7028e3b --- /dev/null +++ b/device/gxx-linux/display/Lcd.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include +#include +#include +#include +#include "Gpio.h" + +class Lcd +{ +private: + Gpio spi_sck; + Gpio spi_sda; + Gpio spi_cs; + Gpio spi_reset; + Gpio spi_rs; + Gpio COM_BOOT0; + +public: + Lcd(); + /*=======写指令========*/ + void Lcd_Transfer_Command(int data1); + + /*--------写数据------------*/ + void Lcd_Transfer_data(int data1); + + /*LCD模块初始化*/ + void Lcd_Initial_Lcd(bool biglcd); + + void Lcd_Address(unsigned char page, unsigned char column); + + /*全屏清屏*/ + void Lcd_Clear_screen(); + + void Lcd_Clear_Half_Screen(bool top); + + //===显示测试画面:例如全显示,隔行显示,隔列显示,雪花显示===== + void Lcd_Test_Display(unsigned char data1, unsigned char data2); + + /*显示128x64点阵图像*/ + void Lcd_Display_Graphic_128x64(unsigned char page, unsigned char column, unsigned char *dp); + + /*显示32x32点阵图像、汉字、生僻字或32x32点阵的其他图标*/ + void Lcd_Display_graphic_32x32(unsigned char page, unsigned char column, unsigned char *dp); + + /*显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标*/ + void Lcd_Display_Graphic_16x16_2(unsigned char reverse,unsigned char page,unsigned char column,unsigned char *dp); + + /*显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标*/ + void Lcd_Display_Graphic_16x16(unsigned char page, unsigned char column, unsigned char *dp,unsigned int wordcount); + + /*显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标*/ + void Lcd_Display_Graphic_8x16(unsigned char page, unsigned char column,unsigned char *dp); + + void Lcd_Display_String_8x16(unsigned int page, unsigned int column, const char *text); + + void Lcd_Display_String_5x8(unsigned int page, unsigned int column, const char *text); + +}; + + diff --git a/device/gxx-linux/display/xmake.lua b/device/gxx-linux/display/xmake.lua new file mode 100644 index 0000000..097a0f7 --- /dev/null +++ b/device/gxx-linux/display/xmake.lua @@ -0,0 +1,9 @@ +add_rules("mode.debug", "mode.release") + +target("display") + set_kind("static") + add_syslinks("pthread") + add_files("*.cpp") + add_packages("common") + add_deps("deviceio", {public = true}) + add_includedirs(".", { public = true}) \ No newline at end of file diff --git a/device/gxx-linux/i2c_key/Makefile b/device/gxx-linux/i2c_key/Makefile new file mode 100644 index 0000000..4f9d455 --- /dev/null +++ b/device/gxx-linux/i2c_key/Makefile @@ -0,0 +1,6 @@ +ch455_key:ch455_key.cpp + g++ $^ -o $@ + +clean: + rm ch455_key + \ No newline at end of file diff --git a/device/gxx-linux/i2c_key/ch455_key b/device/gxx-linux/i2c_key/ch455_key new file mode 100644 index 0000000000000000000000000000000000000000..46666c299f41658d3fbfd3b9cf3183c6fafa71da GIT binary patch literal 19520 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +#define I2C_SDA 43//GPIO1_B3 +#define I2C_SCL 44//GPIO1_B4 +#define I2C_INT 52 + +typedef unsigned char UINT8; +typedef unsigned short UINT16; + +#define STATUS_SUCCESS 0 +#define STATUS_FAILURE -1 + +#define CH455_GET_KEY 0x0700 // 获取按键,返回按键代码 +#define CH455_SYSOFF 0x0400 // 关闭显示、关闭键盘 + +#define CH455_I2C_ADDR 0x40 // CH455的地址 +#define CH455_I2C_MASK 0x3E // CH455的高字节命令掩码 + +#define CH455_BIT_ENABLE 0x01 +//#define CH455_BIT_ENABLE 0x03 // 开启/关闭位 +#define CH455_BIT_SLEEP 0x04 // 睡眠控制位 + + +#define CH455_SYSON ( CH455_SYSOFF | CH455_BIT_ENABLE ) +#define CH455_SLEEPOFF CH455_SYSOFF // 关闭睡眠 +#define CH455_SLEEPON (CH455_SYSOFF|CH455_BIT_SLEEP) // 开启睡眠 + +static unsigned char TxBuf[24] = {0}; +static unsigned char RxBuf[24] = {0}; + +void CH455_I2c_Stop(void); +void CH455_I2C_WrByte(unsigned char IIC_Byte); + +void delay_us(int i) +{ + int j,k; + for(j=0;j>7)&CH455_I2C_MASK)|CH455_I2C_ADDR); + printf("CH455_Write second byte= %02x\n",(UINT8)cmd); + CH455_I2C_WrByte(((UINT8)(cmd>>7)&CH455_I2C_MASK)|CH455_I2C_ADDR); + CH455_I2C_WrByte((UINT8)cmd); //发送数据 + CH455_I2c_Stop();//结束总线 + printf("CH455_Write end...\n"); + printf("\n"); + return 1; +} + +static unsigned char CH455_Read(void)//读取按键值 +{ + printf("CH455_Read start...\n"); + UINT8 keycode; + CH455_I2c_Start(); //启动总线 + printf("write byte= %02x\n",(UINT8)(CH455_GET_KEY>>7)&CH455_I2C_MASK|0x01|CH455_I2C_ADDR); + CH455_I2C_WrByte((UINT8)(CH455_GET_KEY>>7)&CH455_I2C_MASK|0x01|CH455_I2C_ADDR); + keycode = CH455_I2C_RdByte(); //读取数据 + printf("read byte= %02x\n",keycode); + CH455_I2c_Stop(); //结束总线 + printf("CH455_Read end...\n"); + printf("\n"); + return keycode; +} + +void key_Inter(void) +{ + int ret; + int val = 0; + char buf[8]; + int num; + UINT16 key_value; + pollfd pfd; + pfd.fd = -1; + pfd.fd = open("/sys/class/gpio/gpio52/value", O_RDONLY); + if (pfd.fd > 0) + printf("huagao::open sucess,fd = %d\n",pfd.fd); + else + printf("huagao::open failed,fd = %d\n",pfd.fd); + pfd.events = POLLPRI; + num = read(pfd.fd, buf, 8); // This is to clear the avaible read + for(int i=0;i<8;i++) + printf("huagao::buf[%d] = %d\n",i,buf[i]); + + ret = CH455_Write(CH455_SYSON); + printf("CH455_SYSON = %02x\n",(CH455_SYSON)); + printf("CH455_Read() = %02x\n", CH455_Read()); + key_value = 0xff; + while(1) { + ret = poll(&pfd, 1, 1000); + if (ret > 0) + { + printf("--------------------------------------------\n"); + printf("huagao::poll get date.\n"); + printf("huagao::poll ret = %d\n",ret); + /* + POLLIN: 有普通数据或者优先数据可读 + POLLRDNORM: 有普通数据可读 + POLLRDBAND: 有优先数据可读 + POLLPRI: 有紧急数据可读 + POLLOUT: 有普通数据可写 + POLLWRNORM: 有普通数据可写 + POLLWRBAND: 有紧急数据可写 + POLLERR: 有错误发生 + POLLHUP: 有描述符挂起事件发生 + POLLNVAL: 描述符非法 + */ + if (pfd.revents & POLLPRI) + { + lseek(pfd.fd, 0, SEEK_SET); + num = read(pfd.fd, buf, 8); + buf[num - 1] = '\0'; + ret = atoi(buf); + for(int i=0;i<8;i++) + printf("huagao::buf[%d] = %d\n",i,buf[i]); + printf("huagao::atoi(buf) ret = %d\n",ret); + } + key_value = CH455_Read(); + printf("CH455_Read() = %02x\n", key_value); + printf("--------------------------------------------\n"); + printf("\n"); + } + else if(ret == 0) + { + printf("--------------------------------------------\n"); + printf("huagao::ret = %d\n",ret); + printf("huagao::poll time out.\n"); + printf("--------------------------------------------\n"); + printf("\n"); + } + else + { + printf("--------------------------------------------\n"); + printf("huagao::ret = %d\n",ret); + printf("huagao::poll err.\n"); + printf("--------------------------------------------\n"); + printf("\n"); + } + + } +} +int main(void) +{ + system("echo 52 > /sys/class/gpio/export"); + system("echo in > /sys/class/gpio/gpio52/direction"); + system("echo falling > /sys/class/gpio/gpio52/edge"); + key_Inter(); + return 0; +} + + diff --git a/device/gxx-linux/imgproc/CSizedetect.cpp b/device/gxx-linux/imgproc/CSizedetect.cpp index ed51c89..58c4e53 100644 --- a/device/gxx-linux/imgproc/CSizedetect.cpp +++ b/device/gxx-linux/imgproc/CSizedetect.cpp @@ -1,7 +1,5 @@ #include "CSizedetect.h" #include -#include -#include #include "ImageProcess_Public.h" #include "commondef.h" @@ -134,8 +132,7 @@ int CSizedetect::preprocess(cv::Mat &mat, void *unused) { if(!mat.empty()) { - float width, height; - + float width, height; cv::Mat thre; hg::threshold_Mat(mat, thre, 40); cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(8, 1)); diff --git a/device/gxx-linux/imgproc/CSizedetect.h b/device/gxx-linux/imgproc/CSizedetect.h index a574a81..2b16d10 100644 --- a/device/gxx-linux/imgproc/CSizedetect.h +++ b/device/gxx-linux/imgproc/CSizedetect.h @@ -26,15 +26,16 @@ private: {PaperSize::G400_A5R,HGSize{1653,1165}}, {PaperSize::G400_A6,HGSize{826,1165}}, {PaperSize::G400_A6R,HGSize{1165,826}}, - {PaperSize::G400_B4,HGSize{2023,2866}}, + {PaperSize::G400_B4,HGSize{1969,2780}}, {PaperSize::G400_B5,HGSize{1385,1968}}, {PaperSize::G400_B5R,HGSize{1968,1385}}, {PaperSize::G400_B6R,HGSize{1433,1007}}, {PaperSize::G400_B6,HGSize{1007,1433}}, {PaperSize::G400_DOUBLELETTER,HGSize{2200,3400}}, {PaperSize::G400_LEGAL,HGSize{1700,2800}}, - {PaperSize::G400_LETTER,HGSize{1700,2640}}, + {PaperSize::G400_LETTER,HGSize{1700,2198}}, + {PaperSize::G400_LETTERR,HGSize{2198,1700}}, {PaperSize::G400_LONGLETTER,HGSize{2040,2640}}, - {PaperSize::G400_MAXSIZE,HGSize{2338,6614}} + {PaperSize::G400_MAXSIZE,HGSize{2338,8189}} }; }; \ No newline at end of file diff --git a/device/gxx-linux/imgproc/imageencode.cpp b/device/gxx-linux/imgproc/imageencode.cpp index 68b4c8a..9c4b669 100644 --- a/device/gxx-linux/imgproc/imageencode.cpp +++ b/device/gxx-linux/imgproc/imageencode.cpp @@ -28,31 +28,55 @@ JpegImageEncode::JpegImageEncode(bool bwimg, int dpi) { compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); compression_params.push_back(100); - compression_params.push_back(/*cv::CV_IMWRITE_JPEG_RESOLUTION_X*/7); + + compression_params.push_back(cv::IMWRITE_RESOLUTION_X); compression_params.push_back(dpi); - compression_params.push_back(/*cv::CV_IMWRITE_JPEG_RESOLUTION_Y*/8); + compression_params.push_back(cv::IMWRITE_RESOLUTION_Y); compression_params.push_back(dpi); } else{ - compression_params.push_back(/*CV_IMWRITE_PNG_STRATEGY*/17); + compression_params.push_back(CV_IMWRITE_PNG_STRATEGY); compression_params.push_back(cv::IMWRITE_PNG_STRATEGY_FIXED); } m_bwimg = bwimg; } +JpegImageEncode::JpegImageEncode(const char* fmt, int dpi) : fmt_(fmt ? fmt : "") +{ + if(fmt_ == "PNG") + { + compression_params.push_back(CV_IMWRITE_PNG_STRATEGY); + compression_params.push_back(cv::IMWRITE_PNG_STRATEGY_FIXED); + } + else + { + compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); + compression_params.push_back(100); + compression_params.push_back(cv::IMWRITE_RESOLUTION_X); + compression_params.push_back(dpi); + compression_params.push_back(cv::IMWRITE_RESOLUTION_Y); + compression_params.push_back(dpi); + } +} JpegImageEncode::~JpegImageEncode() { } MemoryPtr JpegImageEncode::encode(cv::Mat &image) { VectorMemroyPtr mem = VectorMemroyPtr(new VectorMemroy()); - // StopWatch sw; - printf("encode image(%d * %d): %p - %p\n", image.cols, image.rows, image.data, image.dataend); - // cv::imwrite("beforcompress.jpg",image); - // cv::imencode(m_bwimg ? ".png" : ".jpg", image, mem->buf(), compression_params); - cv::imencode(".jpg", image, mem->buf(), compression_params); + StopWatch sw; + std::string type(m_bwimg ? ".png" : ".jpg"); - //printf("encode time = %0.2f \n", sw.elapsed_ms()); + if(fmt_ == "PNG") + type = ".png"; + else if(fmt_ == "TIFF") + type = ".tiff"; + else + type = ".jpg"; + + cv::imencode(type.c_str(), image, mem->buf(), compression_params); + printf("encode time = %0.2f \n", sw.elapsed_ms()); + return mem; } diff --git a/device/gxx-linux/imgproc/imageencode.h b/device/gxx-linux/imgproc/imageencode.h index 6b3f3b7..d01f271 100644 --- a/device/gxx-linux/imgproc/imageencode.h +++ b/device/gxx-linux/imgproc/imageencode.h @@ -1,6 +1,7 @@ #pragma once #include "iimageencode.h" #include +#include // typedef struct tagBITMAPFILEHEADER { // WORD bfType; @@ -20,8 +21,11 @@ public: class JpegImageEncode : public IImageEncode { + std::string fmt_; + public: JpegImageEncode(bool bwimg, int dpi); + JpegImageEncode(const char* fmt, int dpi); virtual ~JpegImageEncode(); virtual MemoryPtr encode(cv::Mat& image); diff --git a/device/gxx-linux/imgproc/xmake.lua b/device/gxx-linux/imgproc/xmake.lua index 5609ee6..1062827 100644 --- a/device/gxx-linux/imgproc/xmake.lua +++ b/device/gxx-linux/imgproc/xmake.lua @@ -4,10 +4,11 @@ target("gimgproc") set_kind("static") add_syslinks("pthread") add_files("*.cpp") - add_files("ImageProcess/*.cpp") - del_files("ImageProcess/ImageApplyBarCodeRecognition.cpp") - add_includedirs("ImageProcess", {public = true}) - add_links("opencv_core", "opencv_imgproc", "opencv_imgcodecs", "FreeImage",{ public = true}) + add_files("imageprocess/*.cpp") + --del_files("imageprocess/ImageApplyBarCodeRecognition.cpp") + remove_files("imageprocess/ImageApplyBarCodeRecognition.cpp") + add_includedirs("imageprocess", {public = true}) + add_links("opencv_core", "opencv_imgproc", "opencv_imgcodecs", "freeimageplus", "freeimage",{ public = true}) add_includedirs(".", { public = true}) add_defines("_DIRECT_BUILD") add_packages("common") \ No newline at end of file diff --git a/device/gxx-linux/keymonitor/keymonitor.cpp b/device/gxx-linux/keymonitor/keymonitor.cpp new file mode 100644 index 0000000..14362a5 --- /dev/null +++ b/device/gxx-linux/keymonitor/keymonitor.cpp @@ -0,0 +1,204 @@ +#include "keymonitor.h" +#include "Gpio.h" +#include "PinMonitor.h" +#include + +#define STATUS_SUCCESS 0 +#define STATUS_FAILURE -1 + +#define CH455_GET_KEY 0x0700 // 获取按键,返回按键代码 +#define CH455_SYSOFF 0x0400 // 关闭显示、关闭键盘 + +#define CH455_I2C_ADDR 0x40 // CH455的地址 +#define CH455_I2C_MASK 0x3E // CH455的高字节命令掩码 + +#define CH455_BIT_ENABLE 0x01 +//#define CH455_BIT_ENABLE 0x03 // 开启/关闭位 +#define CH455_BIT_SLEEP 0x04 // 睡眠控制位 + + +#define CH455_SYSON ( CH455_SYSOFF | CH455_BIT_ENABLE ) +#define CH455_SLEEPOFF CH455_SYSOFF // 关闭睡眠 +#define CH455_SLEEPON (CH455_SYSOFF|CH455_BIT_SLEEP) // 开启睡眠 + +KeyMonitor::KeyMonitor(std::function keycall) : m_keycall(keycall) +{ + m_gpioi2c_SCL = std::make_shared(44); //I2C_SCL + m_gpioi2c_SCL->setDirection(Gpio::out); + m_gpioi2c_SDA = std::make_shared(43); //I2C_SDA + m_gpioi2c_SDA->setDirection(Gpio::out); + write_cmd(CH455_SYSON); + printf("read_key = %02x\n", read_key()); + setled(HGLed::Led_All_close); + auto pincall=[&](int pin) + { + auto value= read_key(); + printf("Key = %02x pin value = %d \n",value,pin); + if(m_keycall) + m_keycall(value); + }; + m_keymonitor = std::make_shared(52,pincall); +} + +KeyMonitor::~KeyMonitor() +{ + if(m_gpioi2c_SCL.get()) + m_gpioi2c_SCL.reset(); + + if(m_gpioi2c_SDA.get()) + m_gpioi2c_SDA.reset(); + + if(m_keymonitor.get()) + m_keymonitor.reset(); +} + +void KeyMonitor::init() +{ +} + +void KeyMonitor::i2c_start() +{ + m_gpioi2c_SDA->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SDA->setValue(Gpio::GpioLevel::Low); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::Low); + std::this_thread::sleep_for(std::chrono::microseconds(5)); +} + +void KeyMonitor::i2c_write(unsigned char cmd) +{ + unsigned char i; + for(i=0; i<8; i++) + { + //IOWR(I2C_SCL, 0); //钳住I2C总线,准备发送数据 + if(cmd & 0x80) + m_gpioi2c_SDA->setValue(Gpio::GpioLevel::High); + else + m_gpioi2c_SDA->setValue(Gpio::GpioLevel::Low); + + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::Low); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + cmd<<=1; + } + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SDA->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::Low); + std::this_thread::sleep_for(std::chrono::microseconds(5)); +} + +unsigned char KeyMonitor::i2c_read() +{ + unsigned char bytedata = 0; + m_gpioi2c_SDA->setDirection(Gpio::in);//将数据设置为输入模式 + //m_gpioi2c_SDA->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::Low); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + for(int i=0; i<8; i++) + { + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + bytedata <<= 1; + bytedata = bytedata | (m_gpioi2c_SDA->getValue()); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::Low); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + } + m_gpioi2c_SDA->setDirection(Gpio::out); + m_gpioi2c_SDA->setValue(Gpio::GpioLevel::High);////数据线设置回输出模式 + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::Low); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + return bytedata; +} + +void KeyMonitor::i2c_stop() +{ + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::Low); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SDA->setValue(Gpio::GpioLevel::Low); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SCL->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); + m_gpioi2c_SDA->setValue(Gpio::GpioLevel::High); + std::this_thread::sleep_for(std::chrono::microseconds(5)); +} + +void KeyMonitor::write_cmd(unsigned short cmd) +{ + i2c_start(); + i2c_write(((unsigned char)(cmd>>7)&CH455_I2C_MASK)|CH455_I2C_ADDR); + i2c_write(cmd); + i2c_stop(); +} + +unsigned char KeyMonitor::read_key() +{ + unsigned char key=0; + i2c_start(); + i2c_write((unsigned char)(CH455_GET_KEY>>7)&CH455_I2C_MASK|0x01|CH455_I2C_ADDR); + key = i2c_read(); + i2c_stop(); + return key; +} + +std::uint8_t KeyMonitor::getledstate() +{ + return m_ledstate; +} + +void KeyMonitor::setled(HGLed value) +{ + switch (value) + { + case HGLed::Led_All_close: + m_ledstate = 0; + break; +#ifdef G200 + case HGLed::Led_All_open: + m_ledstate = 0xf8; + break; + case HGLed::Led_Count_close: + m_ledstate = m_ledstate & 0xef; + break; + case HGLed::Led_Count_open: + m_ledstate = m_ledstate | 0x10; + break; + case HGLed::Led_DoubleFeed_close: + m_ledstate = m_ledstate & 0xbf; + break; + case HGLed::Led_DoubleFeed_open: + m_ledstate = m_ledstate | 0x40; + break; + case HGLed::Led_Enter_close: + m_ledstate = m_ledstate & 0xf7; + break; + case HGLed::Led_Enter_open: + m_ledstate = m_ledstate | 0x8; + break; + case HGLed::Led_Handle_close: + m_ledstate = m_ledstate & 0xdf; + break; + case HGLed::Led_Handle_open: + m_ledstate = m_ledstate | 0x20; + break; +#endif + default: + break; + } + i2c_start(); + i2c_write(0x6e); + i2c_write(m_ledstate); + i2c_stop(); +} diff --git a/device/gxx-linux/keymonitor/keymonitor.h b/device/gxx-linux/keymonitor/keymonitor.h new file mode 100644 index 0000000..832d8b4 --- /dev/null +++ b/device/gxx-linux/keymonitor/keymonitor.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include "commondef.h" +class PinMonitor; +class Gpio; + +class KeyMonitor +{ +public: +#ifdef G200 + enum class HGKey + { + Key_Enter = 69, + Key_Cancle = 70, + Key_Count = 78, + Key_Handle = 77, + Key_DoubleFeed = 68, + Key_Left = 86, + Key_Menu = 85, + Key_Right = 76, + Key_Clear = 84 + }; +#else + enum class HGKey + { + Key_Enter = 70, + Key_Cancle = 69, + Key_Count = 78, + Key_Menu = 76, + Key_Right = 77, + Key_Clear = 68, + Key_Handle = 3331, + Key_DoubleFeed = 3332, + Key_Left = 3333 + }; +#endif + enum class HGLed + { + Led_Enter_open = 0, + Led_Enter_close, + Led_Count_open, + Led_Count_close, + Led_DoubleFeed_open, + Led_DoubleFeed_close, + Led_Handle_open, + Led_Handle_close, + Led_All_open, + Led_All_close + }; +public: + KeyMonitor(std::function keycall); + void setled(HGLed value); + std::uint8_t getledstate(); + ~KeyMonitor(); +private: + void init(); + void i2c_start(); + void i2c_write(unsigned char cmd); + unsigned char i2c_read(); + void i2c_stop(); + void write_cmd(unsigned short cmd); + unsigned char read_key(); +private: + std::shared_ptr m_keymonitor; + std::shared_ptr m_gpioi2c_SDA; + std::shared_ptr m_gpioi2c_SCL; + std::function m_keycall; + volatile std::uint8_t m_ledstate; +}; \ No newline at end of file diff --git a/device/gxx-linux/keymonitor/xmake.lua b/device/gxx-linux/keymonitor/xmake.lua new file mode 100644 index 0000000..9bd3550 --- /dev/null +++ b/device/gxx-linux/keymonitor/xmake.lua @@ -0,0 +1,9 @@ +add_rules("mode.debug", "mode.release") + +target("keymonitor") + set_kind("static") + add_files("*.cpp") + add_syslinks("pthread") + add_deps("deviceio") + add_packages("common") + add_includedirs(".", { public = true}) \ No newline at end of file diff --git a/device/gxx-linux/mdfusbconfig b/device/gxx-linux/mdfusbconfig deleted file mode 100644 index 59abe808744820d1d9bc0ddbbffd139ab0f18607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9688 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 diff --git a/device/gxx-linux/motor_run/CuoZhiMotor.cpp b/device/gxx-linux/motor_run/CuoZhiMotor.cpp deleted file mode 100644 index de9bf86..0000000 --- a/device/gxx-linux/motor_run/CuoZhiMotor.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "CuoZhiMotor.h" -#include - -CuoZhiMotor::CuoZhiMotor() : Motor(motorPorts_Cuozhi) -{ - m_cfg.GetParams(0,MotorConfig::MTBDType::MT_DRV); - if(Dail().GetValue().dails.in_voltage4 == 0) - m_mttype = MotorConfig::MTBDType::MT_DRV; - else - m_mttype = MotorConfig::MTBDType::MT_TMC; - speedChange(0,1,1); - printf("\nCuo speed = %d ",m_mttype); -} - -CuoZhiMotor::~CuoZhiMotor() -{ - std::cout << "CuoZhiMotor::~CuoZhiMotor()" << std::endl; -} - -void CuoZhiMotor::speedChange(int speed,int dpi ,int iscolor) -{ - printf("\nCuo speed = %d dpi = %d iscolor = %d",speed,dpi,iscolor); - if(speed == 0xff) - { - if(m_mttype == MotorConfig::MTBDType::MT_DRV) - mspCuozhiForward = { .finalPeriod = 1427500,.Fmin = 2027500 ,.stepnum = 30 ,.a = 100 , - .offset = 4 ,.finalDelay = 3000 }; - else - mspCuozhiForward = { .finalPeriod = 1427500/4,.Fmin = 2027500/4 ,.stepnum = 30 ,.a = 100 , - .offset = 4 ,.finalDelay = 3000 }; - } - else{ - auto params = m_cfg.GetMotorSpeedParams(false,m_mttype); - m_speedmode = speed; - for (int i = 0; i < params.size(); i++) - { - if (params[i].dpi == dpi && - params[i].colormode == iscolor && - params[i].speed == (speed+1)) - { - mspCuozhiForward = { .finalPeriod = params[i].mt_param.finalPeriod,.Fmin = params[i].mt_param.Fmin,.stepnum = params[i].mt_param.stepnum,.a = params[i].mt_param.a, - .offset = params[i].mt_param.offset,.finalDelay = params[i].mt_param.finalDelay }; - } - } - } - - printf("\n mspCuozhiForward.finalPeriod %d, mspCuozhiForward.Fmin %d, mspCuozhiForward.stepnum %f , mspCuozhiForward.a %f, mspCuozhiForward.offset %f , mspCuozhiForward.finalDelay %f", - mspCuozhiForward.finalPeriod, mspCuozhiForward.Fmin, mspCuozhiForward.stepnum, mspCuozhiForward.a, mspCuozhiForward.offset, mspCuozhiForward.finalDelay); - delays_forward = speedup_cfg(mspCuozhiForward.finalPeriod, mspCuozhiForward.Fmin, mspCuozhiForward.stepnum, mspCuozhiForward.a, mspCuozhiForward.offset, mspCuozhiForward.finalDelay); - - // if(cuoZhiForwardFinalPeriod.find(dpi) == cuoZhiForwardFinalPeriod.end()) - // dpi = 1; - // mspCuozhiForward = { .finalPeriod = cuoZhiForwardFinalPeriod.at(dpi)[m_speedmode],.Fmin = cuoZhiFmin.at(dpi)[m_speedmode], - // .stepnum = cuoZhiStepNum.at(dpi)[m_speedmode],.a = cuoZhiA.at(dpi)[m_speedmode],.offset = cuoZhiOffset.at(dpi)[m_speedmode], - // .finalDelay = cuoZhiFinalDelay.at(dpi)[m_speedmode] }; - mspCuozhiBackward = { .finalPeriod = cuoZhiBackwardFinalPeriod.at(dpi)[m_speedmode],.Fmin = cuoZhiFmin.at(dpi)[m_speedmode], - .stepnum = cuoZhiStepNum.at(dpi)[m_speedmode],.a = cuoZhiA.at(dpi)[m_speedmode],.offset = cuoZhiOffset.at(dpi)[m_speedmode], - .finalDelay = cuoZhiFinalDelay.at(dpi)[m_speedmode] }; - // delays_forward = speedup_cfg(mspCuozhiForward.finalPeriod, mspCuozhiForward.Fmin, mspCuozhiForward.stepnum, mspCuozhiForward.a, - // mspCuozhiForward.offset, mspCuozhiForward.finalDelay); - delays_backward = speedup_cfg(mspCuozhiBackward.finalPeriod, mspCuozhiBackward.Fmin, mspCuozhiBackward.stepnum, mspCuozhiBackward.a, - mspCuozhiBackward.offset, mspCuozhiBackward.finalDelay); - - } \ No newline at end of file diff --git a/device/gxx-linux/motor_run/CuoZhiMotor.h b/device/gxx-linux/motor_run/CuoZhiMotor.h deleted file mode 100644 index dd89e44..0000000 --- a/device/gxx-linux/motor_run/CuoZhiMotor.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once -#include "Motor.h" -#include - -class CuoZhiMotor : public Motor -{ -public: - CuoZhiMotor(); - ~CuoZhiMotor(); - void speedChange(int speed,int dpi ,int iscolor); - void reset() { - mspCuozhiBackward = {.finalPeriod = 827500, .Fmin = 1407750, .stepnum = 25, .a = 150, .offset = 8, .finalDelay = 3000}; - mspCuozhiForward = {.finalPeriod = 627500, .Fmin = 1407750, .stepnum = 25, .a = 150, .offset = 8, .finalDelay = 3000}; - if(m_mttype == MotorConfig::MTBDType::MT_TMC) - { - mspCuozhiBackward.finalPeriod /= 4; - mspCuozhiBackward.Fmin /= 4; - mspCuozhiForward.finalPeriod /= 4; - mspCuozhiForward.Fmin /= 4; - } - delays_forward = speedup_cfg(mspCuozhiForward.finalPeriod, mspCuozhiForward.Fmin, mspCuozhiForward.stepnum, mspCuozhiForward.a, - mspCuozhiForward.offset, mspCuozhiForward.finalDelay); - forward(); - std::this_thread::sleep_for(std::chrono::milliseconds(300)); - stop(); - delays_backward = speedup_cfg(mspCuozhiBackward.finalPeriod, mspCuozhiBackward.Fmin, mspCuozhiBackward.stepnum, mspCuozhiBackward.a, - mspCuozhiBackward.offset, mspCuozhiBackward.finalDelay); - backward(); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - stop(); - } - - virtual void start() { - forward(); - } - - void forward() { - setDirection(1); - Motor::start(delays_forward, mspCuozhiForward); - } - - void backward() { - setDirection(0); - Motor::start(delays_backward, mspCuozhiBackward); - } - -private: - MotorConfig m_cfg; - const std::map> cuoZhiStepNum = { - {1,{23,25,30,30,30 }}, - {2,{23,25,30,30,30 }}, - {3,{23,25,30,30,30 }}, - }; - const std::map> cuoZhiForwardFinalPeriod = { - {1,{607500,537500,477500,435500,435500}}, - {2,{607500,537500,517500,497500,477500}}, - {3,{607500,537500,527500,477500,307500}}, - };//627500,607500,587500,567500,547500,527500 - const std::map> cuoZhiBackwardFinalPeriod = { - {1,{607500,537500,477500,395500,307500}}, - {2,{607500,587500,527500,477500,307500}}, - {3,{607500,587500,527500,477500,307500}}, - };//707500,607500,587500,567500,547500,527500 - const std::map> cuoZhiFmin = { - {1,{ 1407750,1407750,1407750,1407750,1407750 }}, - {2,{ 1407750,1407750,1407750,1407750,1407750 }}, - {3,{ 1407750,1407750,1407750,1407750,1407750 }}, - }; - const std::map> cuoZhiA = { - {1,{ 180,150,150,130,130 }}, - {2,{ 180,150,150,130,130 }}, - {3,{ 180,150,150,150,150 }}, - }; - const std::map> cuoZhiOffset = { - {1,{ 7,7,7,12,12 }}, - {2,{ 7,7,7,7,7 }}, - {3,{ 7,7,7,7,7 }}, - }; - const std::map> cuoZhiFinalDelay = { - {1,{ 3000,3000,3000,3000,3000 }}, - {2,{ 3000,3000,3000,3000,3000 }}, - {3,{ 3000,3000,3000,3000,3000 }}, - }; - - MotorSpeedParam mspCuozhiForward; - MotorSpeedParam mspCuozhiBackward; - std::vector delays_forward; - std::vector delays_backward; - int m_speedmode; -}; - - diff --git a/device/gxx-linux/motor_run/DevUtil.h b/device/gxx-linux/motor_run/DevUtil.h deleted file mode 100644 index 9018f16..0000000 --- a/device/gxx-linux/motor_run/DevUtil.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once -#include -#include -#include -#include "stringex.hpp" - -template -void write_dev(std::string path, T value) { - std::ofstream ofout(path); - ofout << value; - ofout.close(); -} - -extern int read_dev_i(std::string path); - -extern std::string read_dev_s(std::string path); - -enum PORTS -{ - /* //RK3288 Motor GPIO - CuoZhiMotor_Reset = 56, // GPIO2_A0 MOTO_BOT_RESET_N - CuoZhiMotor_Sleep = 57, // GPIO2_A1 MOTO_BOT_SLEEP_N - CuoZhiMotor_Enable = 58, // GPIO2_A2 MOTO_BOT_ENBL_N - CuoZhiMotor_Direction = 62, // GPIO2_A6 MOTO_BOT_DIR - CuoZhiMotor_Home = 184, // GPIO6_A0 MOTO_BOT_HOME_N - CuoZhiMotor_Fault = 185, // GPIO6_A1 MOTO_BOT_FAULT_N - - ZouZhiMotor_Reset = 64, // GPIO2_B0 MOTO_TOP_RESET_N - ZouZhiMotor_Sleep = 65, // GPIO2_B1 MOTO_TOP_SLEEP_N - ZouZhiMotor_Enable = 66, // GPIO2_B2 MOTO_TOP_ENBL_N - ZouZhiMotor_Direction = 70, // GPIO2_B6 MOTO_TOP_DIR - ZouZhiMotor_Home = 186, // GPIO6_A2 - ZouZhiMotor_Fault = 187, // GPIO6_A3 - */ - - //RK3399 Motor GPIO - MotorPower = 157, // GPIO4_D5 motor power - - CuoZhiMotor_Reset = 151, // GPIO4_C7 BOT - CuoZhiMotor_Enable = 153, // GPIO4_D1 BOT - CuoZhiMotor_Direction = 152, // GPIO4_D0 BOT - - ZouZhiMotor_Reset = 155, // GPIO4_D3 TOP - ZouZhiMotor_Enable = 154, // GPIO4_D2 TOP - ZouZhiMotor_Direction = 52, // GPIO1_C4 TOP -}; - -class DeviceExport { -public: - DeviceExport(); -private: - const int ports[7] = { MotorPower, CuoZhiMotor_Reset, CuoZhiMotor_Enable, CuoZhiMotor_Direction, - ZouZhiMotor_Reset, ZouZhiMotor_Enable, ZouZhiMotor_Direction, - }; - const int pwms[2] = { 1, 2 }; -}; - diff --git a/device/gxx-linux/motor_run/Motor.cpp b/device/gxx-linux/motor_run/Motor.cpp deleted file mode 100644 index 637ea44..0000000 --- a/device/gxx-linux/motor_run/Motor.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "Motor.h" -#include "DevUtil.h" -#include -#include -#include - - -const MotorPorts motorPorts_Zouzhi = { .reset = ZouZhiMotor_Reset, .enable = ZouZhiMotor_Enable, .dir = ZouZhiMotor_Direction, - .pwm = 1}; -const MotorPorts motorPorts_Cuozhi = {.reset = CuoZhiMotor_Reset, .enable = CuoZhiMotor_Enable, .dir = CuoZhiMotor_Direction, - .pwm = 2 }; - -std::vector speedup_cfg(int finalPeriod, int Fmin, int stepnum, int a, int offset, int finalDelay) { - std::vector freqs; - int period = 0; - double delay = ((double)finalDelay) / 1000000.0; - double b = stepnum * delay; - for (int i = 0; i < stepnum; i++) { - b = b - delay; - period = (int)(finalPeriod + (Fmin - finalPeriod) / (1 + exp(-a * b + offset))); - freqs.push_back(period); - //printf("\n period %d",period); - } - return freqs; -} - -Motor::Motor(MotorPorts motorPorts) - : powerpin(MotorPower),resetPin(motorPorts.reset),enablePin(motorPorts.enable),dirPin(motorPorts.dir),pwm(motorPorts.pwm) -{ - powerpin.setDirection(Gpio::out); - resetPin.setDirection(Gpio::out); - enablePin.setDirection(Gpio::out); - dirPin.setDirection(Gpio::out); - powerpin.setValue(Gpio::High); - resetPin.setValue(Gpio::High); - enablePin.setValue(Gpio::High); - std::cout << "Motor::Motor(MotorPorts motorPorts)" << std::endl; -} - -Motor:: ~Motor() -{ - stop(); - std::cout << "Motor::~Motor()" << std::endl; -} - -void Motor::start() { - enablePin.setValue(Gpio::Low); - pwm.enable(true); -} - -void Motor::stop() { - enablePin.setValue(Gpio::High); - pwm.enable(false); -} - -void Motor::pause() { - enablePin.setValue(Gpio::Low); - pwm.enable(false); -} - -void Motor::setDirection(int dir) { - dirPin.setValue((Gpio::GpioLevel)dir); -} - -void Motor::setSpeed(int value) { - pwm.setFreq(value); -} - - diff --git a/device/gxx-linux/motor_run/Motor.h b/device/gxx-linux/motor_run/Motor.h deleted file mode 100644 index 101d201..0000000 --- a/device/gxx-linux/motor_run/Motor.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once -#include -#include -#include -#include "Gpio.h" -#include "Pwm.h" -#include "MotorConfig.h" -#include "commondef.h" -#include "dailex.hpp" - - -struct MotorPorts -{ - int reset; - int enable; - int dir; - int pwm; -}; - -extern const MotorPorts motorPorts_Zouzhi; -extern const MotorPorts motorPorts_Cuozhi; - -class Motor -{ -public: - Motor(MotorPorts motorPorts); - virtual ~Motor(); -protected: - Gpio powerpin; - Gpio resetPin; - //Gpio sleepPin; - Gpio enablePin; - Gpio dirPin; - //Gpio homePin; - //Gpio faultPin; - - Pwm pwm; - - MotorConfig::MTBDType m_mttype; - void start(std::vector& delay_s, const MotorSpeedParam& msp) - { - if (!delay_s.empty()) { - std::vector::iterator iter = delay_s.begin(); - enablePin.setValue(Gpio::Low); - pwm.setFreq(PWM_PERIOD / (*iter)); - pwm.enable(true); - std::this_thread::sleep_for(std::chrono::microseconds((int)msp.finalDelay)); - while (++iter != delay_s.end()) { - pwm.setFreq(PWM_PERIOD / (*iter)); - std::this_thread::sleep_for(std::chrono::microseconds((int)msp.finalDelay)); - } - } - pwm.setFreq(PWM_PERIOD / msp.finalPeriod); - } - -public: - virtual void start(); - - void stop(); - - void pause(); - - void setDirection(int dir); - - void setSpeed(int value); - - static void enablePower(bool bEnable); - -}; -extern std::vector speedup_cfg(int finalPeriod, int Fmin, int stepnum, int a, int offset, int finalDelay); - - diff --git a/device/gxx-linux/motor_run/MotorConfig.h b/device/gxx-linux/motor_run/MotorConfig.h deleted file mode 100644 index bf0f96d..0000000 --- a/device/gxx-linux/motor_run/MotorConfig.h +++ /dev/null @@ -1,367 +0,0 @@ -#pragma once -#include -#include "json.hpp" -#include -#include - -using json= nlohmann::json; - -struct MotorSpeedParam -{ - int finalPeriod; - int Fmin; - float stepnum; - float a; - float offset; - float finalDelay; - float acceleration_time; -}; - -struct MotorSpeedParamEx -{ - MotorSpeedParam mt_param; - int speed; - int colormode; - int dpi; - int sp; -}; - - - - -#ifndef WIN32 -#define MT_DRV888_CUO_PATH "/usr/local/huago/drv888_cuo.json" -#define MT_DRV888_ZOU_PATH "/usr/local/huago/drv888_zou.json" -#define MT_TMC216_CUO_PATH "/usr/local/huago/tmc216_cuo.json" -#define MT_TMC216_ZOU_PATH "/usr/local/huago/tmc216_zou.json" -#else -#define MT_DRV888_CUO_PATH "drv888_cuo.json" -#define MT_DRV888_ZOU_PATH "drv888_zou.json" -#define MT_TMC216_CUO_PATH "tmc216_cuo.json" -#define MT_TMC216_ZOU_PATH "tmc216_zou.json" -#endif -#ifdef G300 - -static std::vector m_motor_params{ - //drv_888 - {{.finalPeriod = 754200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 1,.sp = 5910},//40 ppm 搓纸 - {{.finalPeriod = 754200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 1,.sp = 1970}, - {{.finalPeriod = 804300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 2,.sp = 3942}, - {{.finalPeriod = 804300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 2,.sp = 1314}, - {{.finalPeriod = 804300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 3,.sp = 3942}, - {{.finalPeriod = 804300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 3,.sp = 1314}, - - {{.finalPeriod = 705300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 1,.sp = 4509},//50 ppm 搓纸 - {{.finalPeriod = 705300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 1,.sp = 1503}, - {{.finalPeriod = 705300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 2,.sp = 3009}, - {{.finalPeriod = 705300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 2,.sp = 1003}, - {{.finalPeriod = 705300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 3,.sp = 3009}, - {{.finalPeriod = 705300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 3,.sp = 1003}, - - {{.finalPeriod = 656200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 1,.sp = 3702},//60 ppm 搓纸 - {{.finalPeriod = 656200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 1,.sp = 1234}, - {{.finalPeriod = 656300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 2,.sp = 2446}, - {{.finalPeriod = 656300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 2,.sp = 822}, - {{.finalPeriod = 656300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 3,.sp = 2446}, - {{.finalPeriod = 656300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 3,.sp = 822}, - - {{.finalPeriod = 527200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 1,.sp = 3129},//70 ppm 搓纸 - {{.finalPeriod = 527200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 1,.sp = 1043}, - {{.finalPeriod = 527300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 2,.sp = 2446}, - {{.finalPeriod = 527300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 2,.sp = 859}, - {{.finalPeriod = 527300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 3,.sp = 2446}, - {{.finalPeriod = 527300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 3,.sp = 859}, - - {{.finalPeriod = 527200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 1,.sp = 3129},//80 ppm 搓纸 - {{.finalPeriod = 527200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 1,.sp = 1043}, - {{.finalPeriod = 527300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 2,.sp = 2446}, - {{.finalPeriod = 527300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 2,.sp = 859}, - {{.finalPeriod = 527300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 3,.sp = 2446}, - {{.finalPeriod = 527300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 3,.sp = 859}, - - {{.finalPeriod = 504200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 1,.sp = 5910},//40 ppm 走纸 - {{.finalPeriod = 504200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 1,.sp = 1970}, - {{.finalPeriod = 504300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 2,.sp = 3942}, - {{.finalPeriod = 504300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 2,.sp = 1314}, - {{.finalPeriod = 504300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 3,.sp = 3942}, - {{.finalPeriod = 504300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 3,.sp = 1314}, - - {{.finalPeriod = 385300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 1,.sp = 4509},//50 ppm 走纸 - {{.finalPeriod = 385300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 1,.sp = 1503}, - {{.finalPeriod = 385300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 2,.sp = 3009}, - {{.finalPeriod = 385300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 2,.sp = 1003}, - {{.finalPeriod = 385300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 3,.sp = 3009}, - {{.finalPeriod = 385300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 3,.sp = 1003}, - - {{.finalPeriod = 316200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 1,.sp = 3702},//60 ppm 走纸 - {{.finalPeriod = 316200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 1,.sp = 1234}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 2,.sp = 2466}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 2,.sp = 822}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 3,.sp = 2466}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 3,.sp = 822}, - - {{.finalPeriod = 267200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 1,.sp = 3129},//70 ppm 走纸 - {{.finalPeriod = 267200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 1,.sp = 1043}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 2,.sp = 2466}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 2,.sp = 822}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 3,.sp = 2466}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 3,.sp = 822}, - - {{.finalPeriod = 267200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 1,.sp = 3129},//80 ppm 走纸 - {{.finalPeriod = 267200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 1,.sp = 1043}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 2,.sp = 2466}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 2,.sp = 822}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 3,.sp = 2466}, - {{.finalPeriod = 316300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 3,.sp = 822}, - - //tmc - {{.finalPeriod = 184200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 1,.sp = 5814},//40 ppm 搓纸 - {{.finalPeriod = 184200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 1,.sp = 1938}, - {{.finalPeriod = 204300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 2,.sp = 3879}, - {{.finalPeriod = 204300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 2,.sp = 1293}, - {{.finalPeriod = 204300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 3,.sp = 3879}, - {{.finalPeriod = 204300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 3,.sp = 1293}, - - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 1,.sp = 4455},//50 ppm 搓纸 - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 1,.sp = 1485}, - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 2,.sp = 2975}, - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 2,.sp = 991}, - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 3,.sp = 2972}, - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 3,.sp = 991}, - - {{.finalPeriod = 166200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 1,.sp = 3570},//60 ppm 搓纸 - {{.finalPeriod = 166200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 1,.sp = 1190}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 2,.sp = 2445}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 2,.sp = 815}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 3,.sp = 2445}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 3,.sp = 815}, - - {{.finalPeriod = 137200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 1,.sp = 3126},//70 ppm 搓纸 - {{.finalPeriod = 137200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 1,.sp = 1042}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 2,.sp = 2445}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 2,.sp = 815}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 3,.sp = 2445}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 3,.sp = 815}, - - {{.finalPeriod = 137200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 1,.sp = 3126},//80 ppm 搓纸 - {{.finalPeriod = 137200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 1,.sp = 1042}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 2,.sp = 2445}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 2,.sp = 815}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 3,.sp = 2445}, - {{.finalPeriod = 166300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 3,.sp = 815}, - - {{.finalPeriod = 124200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 1,.sp = 5814},//40 ppm 走纸 - {{.finalPeriod = 124200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 1,.sp = 1938}, - {{.finalPeriod = 124300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 2,.sp = 3879}, - {{.finalPeriod = 124300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 2,.sp = 1293}, - {{.finalPeriod = 124300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 3,.sp = 3879}, - {{.finalPeriod = 124300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 3,.sp = 1293}, - - {{.finalPeriod = 95200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 1,.sp = 4455},//50 ppm 走纸 - {{.finalPeriod = 95200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 1,.sp = 1485}, - {{.finalPeriod = 95200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 2,.sp = 2975}, - {{.finalPeriod = 95200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 2,.sp = 991}, - {{.finalPeriod = 95200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 3,.sp = 2975}, - {{.finalPeriod = 95200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 3,.sp = 991}, - - {{.finalPeriod = 76200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 1,.sp = 3570},//60 ppm 走纸 - {{.finalPeriod = 76200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 1,.sp = 1190}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 2,.sp = 2445}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 2,.sp = 815}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 3,.sp = 2445}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 3,.sp = 815}, - - {{.finalPeriod = 66720, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 1,.sp = 3126},//70 ppm 走纸 - {{.finalPeriod = 66720, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 1,.sp = 1042}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 2,.sp = 2445}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 2,.sp = 815}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 3,.sp = 2445}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 3,.sp = 815}, - - {{.finalPeriod = 66720, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 1,.sp = 3126},//80 ppm 走纸 - {{.finalPeriod = 66720, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 1,.sp = 1042}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 2,.sp = 2445}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 2,.sp = 815}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 3,.sp = 2445}, - {{.finalPeriod = 78300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 3,.sp = 815}, -}; -#else - -static std::vector m_motor_params{ - //drv_888 - {{.finalPeriod = 754200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 1,.sp = 7290},//40 ppm 搓纸 - {{.finalPeriod = 754200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 1,.sp = 2430}, - {{.finalPeriod = 804300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 2,.sp = 4869}, - {{.finalPeriod = 804300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 2,.sp = 1623}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 3,.sp = 1583}, - - {{.finalPeriod = 735200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 1,.sp = 5870},//50 ppm 搓纸 - {{.finalPeriod = 735200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 1,.sp = 1950}, - {{.finalPeriod = 735300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 2,.sp = 3909}, - {{.finalPeriod = 735300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 2,.sp = 1303}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 3,.sp = 1583}, - - {{.finalPeriod = 686200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 1,.sp = 5004},//60 ppm 搓纸 - {{.finalPeriod = 686200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 1,.sp = 1688}, - {{.finalPeriod = 706300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 2,.sp = 3248}, - {{.finalPeriod = 706300, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 2,.sp = 1080}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 3,.sp = 1583}, - - {{.finalPeriod = 527200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 1,.sp = 3864},//70 ppm 搓纸 - {{.finalPeriod = 527200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 1,.sp = 1287}, - {{.finalPeriod = 527200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 2,.sp = 2580}, - {{.finalPeriod = 527200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 2,.sp = 859}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 3,.sp = 1583}, - - {{.finalPeriod = 508200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 1,.sp = 3735},//80 ppm 搓纸 - {{.finalPeriod = 508200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 1,.sp = 1245}, - {{.finalPeriod = 508200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 2,.sp = 2490}, - {{.finalPeriod = 508200, .Fmin = 1407500, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 2,.sp = 830}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 1006000, .Fmin = 1407500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 3000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 3,.sp = 1583}, - - {{.finalPeriod = 504200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 1,.sp = 7290},//40 ppm 走纸 - {{.finalPeriod = 504200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 1,.sp = 2430}, - {{.finalPeriod = 504300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 2,.sp = 4869}, - {{.finalPeriod = 504300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 2,.sp = 1623}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 3,.sp = 1583}, - - {{.finalPeriod = 385200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 1,.sp = 6050},//50 ppm 走纸 - {{.finalPeriod = 405200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 1,.sp = 1950}, - {{.finalPeriod = 405300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 2,.sp = 3909}, - {{.finalPeriod = 405300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 2,.sp = 1303}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 3,.sp = 1583}, - - {{.finalPeriod = 346200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 1,.sp = 5004},//60 ppm 走纸 - {{.finalPeriod = 346200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 1,.sp = 1688}, - {{.finalPeriod = 336300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 2,.sp = 3248}, - {{.finalPeriod = 336300, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 2,.sp = 1080}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 3,.sp = 1583}, - - {{.finalPeriod = 267200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 1,.sp = 3864},//70 ppm 走纸 - {{.finalPeriod = 267200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 1,.sp = 1287}, - {{.finalPeriod = 267200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 2,.sp = 2580}, - {{.finalPeriod = 267200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 2,.sp = 859}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 3,.sp = 1583}, - - {{.finalPeriod = 258200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 1,.sp = 3735},//80 ppm 走纸 - {{.finalPeriod = 258200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 1,.sp = 1245}, - {{.finalPeriod = 258200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 2,.sp = 2490}, - {{.finalPeriod = 258200, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 2,.sp = 830}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 3,.sp = 4749}, - {{.finalPeriod = 656000, .Fmin = 1607500, .stepnum = 30, .a = 200, .offset = 7, .finalDelay = 3000, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 3,.sp = 1583}, - - //tmc - {{.finalPeriod = 184200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 1,.sp = 7200},//40 ppm 搓纸 - {{.finalPeriod = 184200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 1,.sp = 2400}, - {{.finalPeriod = 204300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 2,.sp = 4800}, - {{.finalPeriod = 204300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 2,.sp = 1598}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 3,.sp = 1586}, - - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 1,.sp = 6050},//50 ppm 搓纸 - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 1,.sp = 2026}, - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 2,.sp = 4053}, - {{.finalPeriod = 185200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 2,.sp = 1350}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 3,.sp = 1586}, - - {{.finalPeriod = 176200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 1,.sp = 4978},//60 ppm 搓纸 - {{.finalPeriod = 176200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 1,.sp = 1659}, - {{.finalPeriod = 176300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 2,.sp = 3330}, - {{.finalPeriod = 176300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 2,.sp = 1110}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 3,.sp = 1586}, - - {{.finalPeriod = 137200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 1,.sp = 3858},//70 ppm 搓纸 - {{.finalPeriod = 137200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 1,.sp = 1286}, - {{.finalPeriod = 137300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 2,.sp = 2570}, - {{.finalPeriod = 137300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 2,.sp = 857}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 3,.sp = 1586}, - - {{.finalPeriod = 128200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 1,.sp = 3750},//80 ppm 搓纸 - {{.finalPeriod = 128200, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 1,.sp = 1250}, - {{.finalPeriod = 128300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 2,.sp = 2498}, - {{.finalPeriod = 128300, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 2,.sp = 832}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 251600, .Fmin = 351875, .stepnum = 30, .a = 150, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 3,.sp = 1586}, - - {{.finalPeriod = 124200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 1,.sp = 7200},//40 ppm 走纸 - {{.finalPeriod = 124200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 1,.sp = 2400}, - {{.finalPeriod = 124300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 2,.sp = 4800}, - {{.finalPeriod = 124300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 2,.sp = 1598}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 1,.colormode = 1,.dpi = 3,.sp = 1586}, - - {{.finalPeriod = 105200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 1,.sp = 6050},//50 ppm 走纸 - {{.finalPeriod = 105200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 1,.sp = 2026}, - {{.finalPeriod = 105200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 2,.sp = 4053}, - {{.finalPeriod = 105200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 2,.sp = 1350}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 2,.colormode = 1,.dpi = 3,.sp = 1586}, - - {{.finalPeriod = 86200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 1,.sp = 4978},//60 ppm 走纸 - {{.finalPeriod = 86200, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 1,.sp = 1659}, - {{.finalPeriod = 86300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 2,.sp = 3330}, - {{.finalPeriod = 86300, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 2,.sp = 1110}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 3,.colormode = 1,.dpi = 3,.sp = 1586}, - - {{.finalPeriod = 66720, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 1,.sp = 3858},//70 ppm 走纸 - {{.finalPeriod = 66720, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 1,.sp = 1286}, - {{.finalPeriod = 66730, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 2,.sp = 2572}, - {{.finalPeriod = 66730, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 2,.sp = 857}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 4,.colormode = 1,.dpi = 3,.sp = 1586}, - - {{.finalPeriod = 64820, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 1,.sp = 3750},//80 ppm 走纸 - {{.finalPeriod = 64820, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 1,.sp = 1250}, - {{.finalPeriod = 64830, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 2,.sp = 2498}, - {{.finalPeriod = 64830, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 2,.sp = 832}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 0,.dpi = 3,.sp = 4760}, - {{.finalPeriod = 164600, .Fmin = 401875, .stepnum = 30, .a = 200, .offset = 9, .finalDelay = 2500, .acceleration_time =2},.speed = 5,.colormode = 1,.dpi = 3,.sp = 1586}, -}; -#endif - - -class MotorConfig -{ -private: - std::vector m_cuoParams; - std::vector m_zouParams; - const std::vector m_jsonpaths={ - MT_DRV888_CUO_PATH, - MT_DRV888_ZOU_PATH, - MT_TMC216_CUO_PATH, - MT_TMC216_ZOU_PATH - }; - -public: - enum class MTBDType - { - MT_TMC, - MT_DRV - }; - MotorConfig(/* args */); - ~MotorConfig(); - std::string GetParams(bool bzouzhi,MTBDType mttype); - void SetParams(bool bzouzhi,MTBDType mttype,MotorSpeedParamEx& param); - std::vector GetMotorSpeedParams(bool bzouzhi,MTBDType mttype); - std::vector GetMotorSpeedParams(const std::string& json_str); - void to_json(MotorSpeedParamEx& param,json& j); - void from_json(json& j,MotorSpeedParamEx& param); - void reset_json(); -private: - void initconfigfile(); - -}; - diff --git a/device/gxx-linux/motor_run/MotorControl.cpp b/device/gxx-linux/motor_run/MotorControl.cpp deleted file mode 100644 index 42b9dfc..0000000 --- a/device/gxx-linux/motor_run/MotorControl.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "CuoZhiMotor.h" -#include "ZouZhiMotor.h" -#include "MotorControl.h" - -MotorControl::MotorControl() -{ - m_zzm.reset(new ZouZhiMotor()); - m_czm.reset(new CuoZhiMotor()); - //m_czm->reset(); -} -MotorControl::~MotorControl() -{ - m_zzm->stop(); - m_czm->stop(); - m_czm.reset(); - m_zzm.reset(); -} -void MotorControl::MotorRun(MotorOption option) -{ - switch (option) - { - case MotorOption::CZ_Reset : - m_czm->reset(); - break; - case MotorOption::CZ_Forward : - m_czm->forward(); - break; - case MotorOption::CZ_Backward : - m_czm->backward(); - break; - case MotorOption::CZ_Pause: - m_czm->pause(); - break; - case MotorOption::CZ_Stop : - m_czm->stop(); - break; - case MotorOption::ZZ_Backward : - m_zzm->setDirection(1); - m_zzm->start(); - break; - case MotorOption::ZZ_Forward : - m_zzm->setDirection(0); - m_zzm->start(); - break; - case MotorOption::ZZ_Stop : - m_zzm->stop(); - break; - default: - break; - } -} - -void MotorControl::setzzspeed(int zuo_spmode,int dpi,int iscolor){ - m_zzm->speedChange(zuo_spmode,dpi,iscolor); -} -void MotorControl::setczspeed(int cuo_spmode,int dpi,int iscolor){ - m_czm->speedChange(cuo_spmode,dpi,iscolor); -} diff --git a/device/gxx-linux/motor_run/MotorControl.h b/device/gxx-linux/motor_run/MotorControl.h deleted file mode 100644 index 9111b90..0000000 --- a/device/gxx-linux/motor_run/MotorControl.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -class CuoZhiMotor; -class ZouZhiMotor; -struct MotorSpeedParam; - - -class MotorControl -{ -public: - enum MotorOption : int{ - CZ_Reset, - CZ_Forward, - CZ_Backward, - CZ_Pause, - CZ_Stop, - ZZ_Forward, - ZZ_Backward, - ZZ_Stop, - }; - MotorControl(); - ~MotorControl(); - void setzzspeed(int zuo_spmode,int dpi,int iscolor); - void setczspeed(int cuo_spmode,int dpi,int iscolor); - void MotorRun(MotorOption option); -private: - std::unique_ptr m_czm; - std::unique_ptr m_zzm; -}; diff --git a/device/gxx-linux/motor_run/Pwm.cpp b/device/gxx-linux/motor_run/Pwm.cpp deleted file mode 100644 index 2125069..0000000 --- a/device/gxx-linux/motor_run/Pwm.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "Pwm.h" -#include "DevUtil.h" -#include - -#define PWMPATH "%s%d/pwm0/%s" - -Pwm::Pwm(int port) -{ - path_enable = string_format(PWMPATH, path_base.c_str(), port, path_enable.c_str()); - path_duty_cycle = string_format(PWMPATH, path_base.c_str(), port, path_duty_cycle.c_str()); - path_period = string_format(PWMPATH, path_base.c_str(), port, path_period.c_str()); - printf("Pwm::Pwm(int port = %d)\n",port); -} - -Pwm::~Pwm() -{ - std::cout << "Pwm::~Pwm()" << std::endl; -} - -void Pwm::setFreq(int freq) -{ - int value = PWM_PERIOD / freq; - write_dev(path_period, value); - write_dev(path_duty_cycle, value / 2); -} - -int Pwm::getFreq() -{ - return PWM_PERIOD/read_dev_i(path_period); -} - -void Pwm::enable(bool bEnable) -{ - write_dev(path_enable, bEnable); -} - -bool Pwm::isEnable() -{ - return (bool)read_dev_i(path_enable); -} diff --git a/device/gxx-linux/motor_run/Pwm.h b/device/gxx-linux/motor_run/Pwm.h deleted file mode 100644 index c31bfbf..0000000 --- a/device/gxx-linux/motor_run/Pwm.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include -#define PWM_PERIOD 1000000000 - -class Pwm -{ -public: - Pwm(int port); - ~Pwm(); - - void setFreq(int freq); - int getFreq(); - - void enable(bool bEnable); - bool isEnable(); - -private: - const std::string path_base = "/sys/class/pwm/pwmchip"; - std::string path_enable = "enable"; - std::string path_duty_cycle = "duty_cycle"; - std::string path_period = "period"; -}; \ No newline at end of file diff --git a/device/gxx-linux/motor_run/ZouZhiMotor.cpp b/device/gxx-linux/motor_run/ZouZhiMotor.cpp deleted file mode 100644 index c497615..0000000 --- a/device/gxx-linux/motor_run/ZouZhiMotor.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "ZouZhiMotor.h" -#include -#include - -ZouZhiMotor::ZouZhiMotor() : Motor(motorPorts_Zouzhi) -{ - speedChange(0,1,1); - if(Dail().GetValue().dails.in_voltage4 == 0) - m_mttype = MotorConfig::MTBDType::MT_DRV; - else - m_mttype = MotorConfig::MTBDType::MT_TMC; -} - -ZouZhiMotor::~ZouZhiMotor() -{ - std::cout << "ZouZhiMotor::~ZouZhiMotor()" << std::endl; -} - -void ZouZhiMotor::start() -{ - Motor::start(delays, mspZhouzhi); -} - -void ZouZhiMotor::speedChange(int speed,int dpi ,int iscolor) -{ - // if(zouZhiFinalDelay.find(dpi)==zouZhiFinalDelay.end()) - // dpi = 1; - // m_speedmode = speed; - // printf(" \n speed %d",speed); - // mspZhouzhi = { .finalPeriod = zouZhiFinalPeriod.at(dpi)[m_speedmode],.Fmin = zouZhiFmin.at(dpi)[m_speedmode],.stepnum = zouZhiStepNum.at(dpi)[m_speedmode],.a = zouZhiA.at(dpi)[m_speedmode], - // .offset = zouZhiOffset.at(dpi)[m_speedmode],.finalDelay = zouZhiFinalDelay.at(dpi)[m_speedmode] }; - // std::cout<< ".finalPeriod = "< delays; - MotorSpeedParam mspZhouzhi; - MotorConfig m_cfg; - int m_speedmode; - - const std::map> zouZhiFinalPeriod ={ - {1,{ 586500,420500,330000,245000,205000 }}, - {2,{ 916500,656500,530500,386500,347000 }}, - {3,{ 756500,756500,756500,756500,756500 }}, - };//756500,556500,426500,336500,286500,230500 //265000 - const std::map> zouZhiFmin ={ - {1,{ 1607750,1607750,1607750,1607750,1607750 }}, - {2,{ 1607750,1607750,1607750,1607750,1607750 }}, - {3,{ 1607750,1607750,1607750,1607750,1607750 }}, - };//1607750,1607750,1607750,1607750,1607750,1607750 - const std::map> zouZhiStepNum ={ - { 1, { 23,23,30,30,30 }}, - { 2, { 30,30,30,30,30 }}, - { 3, { 30,30,30,30,30 }}, - }; - const std::map> zouZhiA = { - {1,{ 200,200,200,200,200 }}, - {2,{ 200,200,200,200,200 }}, - {3,{ 200,200,200,200,200 }}, - }; - const std::map> zouZhiOffset = { - {1,{ 7,7,7,7,9 }}, - {2,{ 7,7,7,7,7 }}, - {3,{ 7,7,7,7,7 }}, - }; - const std::map> zouZhiFinalDelay = { - {1,{ 2500,2500,2500,2500,2500 }}, - {2,{ 2500,2500,2500,2500,2500 }}, - {3,{ 2500,2500,2500,2500,2500 }}, - }; -}; - - - diff --git a/device/gxx-linux/motor_run/main.cpp b/device/gxx-linux/motor_run/main.cpp deleted file mode 100644 index 4bb4863..0000000 --- a/device/gxx-linux/motor_run/main.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "DevUtil.h" -#include "Pwm.h" -#include "ZouZhiMotor.h" -#include "CuoZhiMotor.h" - - -int main(int argc,char **argv) { - - //DeviceExport(); /*类里面的构造函数可以直接调用*/ - DeviceExport d1; - ZouZhiMotor zzm; - CuoZhiMotor czm; - std::string instring; - do { - printf("1.cuozhi motor reset\n"); - printf("2.cuozhi motor forward\n"); - printf("3.cuozhi motor reverse\n"); - printf("4.cuozhi motor stop\n"); - printf("5.zouzhi motor forward\n"); - printf("6.zouzhi motor reverse\n"); - printf("7.zouzhi motor stop\n"); - printf(":"); - std::getline(std::cin, instring); - if (instring == "1") { - czm.reset(); - } - if (instring == "2") { - czm.forward(); - } - if (instring == "3") { - czm.backward(); - } - if (instring == "4") { - czm.stop(); - } - if (instring == "5") { - zzm.setDirection(0); - zzm.start(); - } - if (instring == "6") { - zzm.setDirection(1); - zzm.start(); - } - if (instring == "7") { - zzm.stop(); - } - }while(1); - return 0; -} diff --git a/device/gxx-linux/motor_run/xmake.lua b/device/gxx-linux/motor_run/xmake.lua deleted file mode 100644 index 68a3eeb..0000000 --- a/device/gxx-linux/motor_run/xmake.lua +++ /dev/null @@ -1,89 +0,0 @@ -add_rules("mode.debug", "mode.release") - -target("motor_run") - set_kind("static") - add_files("Motor.cpp") - add_files("DevUtil.cpp") - add_files("ZouZhiMotor.cpp") - add_files("CuoZhiMotor.cpp") - add_files("Gpio.cpp") - add_files("Pwm.cpp") - add_files("MotorControl.cpp") - add_files("MotorConfig.cpp") - add_includedirs(".", { public = true}) - add_includedirs("../packages/common.pkg/include", { public = true}) - --add_packages("common") -target("main") - set_kind("binary") - add_files("main.cpp") - add_deps("motor_run") - --- --- If you want to known more usage about xmake, please see https://xmake.io --- --- ## FAQ --- --- You can enter the project directory firstly before building project. --- --- $ cd projectdir --- --- 1. How to build project? --- --- $ xmake --- --- 2. How to configure project? --- --- $ xmake f -p [macosx|linux|iphoneos ..] -a [x86_64|i386|arm64 ..] -m [debug|release] --- --- 3. Where is the build output directory? --- --- The default output directory is `./build` and you can configure the output directory. --- --- $ xmake f -o outputdir --- $ xmake --- --- 4. How to run and debug target after building project? --- --- $ xmake run [targetname] --- $ xmake run -d [targetname] --- --- 5. How to install target to the system directory or other output directory? --- --- $ xmake install --- $ xmake install -o installdir --- --- 6. Add some frequently-used compilation flags in xmake.lua --- --- @code --- -- add debug and release modes --- add_rules("mode.debug", "mode.release") --- --- -- add macro defination --- add_defines("NDEBUG", "_GNU_SOURCE=1") --- --- -- set warning all as error --- set_warnings("all", "error") --- --- -- set language: c99, c++11 --- set_languages("c99", "c++11") --- --- -- set optimization: none, faster, fastest, smallest --- set_optimize("fastest") --- --- -- add include search directories --- add_includedirs("/usr/include", "/usr/local/include") --- --- -- add link libraries and search directories --- add_links("tbox") --- add_linkdirs("/usr/local/lib", "/usr/lib") --- --- -- add system link libraries --- add_syslinks("z", "pthread") --- --- -- add compilation and link flags --- add_cxflags("-stdnolib", "-fno-strict-aliasing") --- add_ldflags("-L/usr/local/lib", "-lpthread", {force = true}) --- --- @endcode --- - diff --git a/device/gxx-linux/motorboard/FeedControl.cpp b/device/gxx-linux/motorboard/FeedControl.cpp new file mode 100644 index 0000000..a434180 --- /dev/null +++ b/device/gxx-linux/motorboard/FeedControl.cpp @@ -0,0 +1,69 @@ +#include "FeedControl.h" +#include +#include + +FeedControl::FeedControl(/* args */) : m_thre(0.3) +{ +} + +FeedControl::~FeedControl() +{ +} + +FeedControl::FeedMode FeedControl::GetPredictFeedMode() +{ + return calcFeedMode(); +} + +FeedControl::FeedMode FeedControl::calcFeedMode() +{ + FeedMode mode = FeedMode::FMode_NOChange; + auto infos = m_sessioninfo.GetRecordInfo(); + if (infos.size() < 10) //样本数量大于10了 才做分纸模式分析切换 + return mode; + + unsigned int nDoubleFeedTimes, nJamTimes, nFeedErrorTimes, nTotalScanned; + nDoubleFeedTimes = nJamTimes = nFeedErrorTimes = nTotalScanned = 0; + for (auto &item : infos) + { + if (!item.NormalDone) + { + if (item.DoubleFeed) + nDoubleFeedTimes++; + if (item.Jammed) + nJamTimes++; + if (item.FeedError) + nFeedErrorTimes++; + + nTotalScanned += item.CurrentScaned; + } + } + + double percentHigh = nDoubleFeedTimes / 10.0; + double percentLow = nFeedErrorTimes / 10.0; + printf("\n percentHigh : %f percentLow : %f" , percentHigh,percentLow); + if (percentHigh >= m_thre || percentLow >= m_thre) + { + mode = percentHigh >= percentLow ? FeedMode::FMode_High : FeedMode::FMode_Low; + if(fabs(percentHigh - percentLow) < 0.2) + mode = FeedMode::FMode_Mid; + ResetMode(); + } + printf("\n Calc Feed Mode : %d" , (int)mode); + return mode; +} + +void FeedControl::AppendPattern(MotorSessionInfo::MBTaskRecordInfo info) +{ + m_sessioninfo.UpdateRecordInfo(info); +} + +void FeedControl::SetThre(double thre) +{ + m_thre = thre; +} + +void FeedControl::ResetMode() +{ + m_sessioninfo.RemoveInfos(); +} \ No newline at end of file diff --git a/device/gxx-linux/motorboard/FeedControl.h b/device/gxx-linux/motorboard/FeedControl.h new file mode 100644 index 0000000..771a05b --- /dev/null +++ b/device/gxx-linux/motorboard/FeedControl.h @@ -0,0 +1,31 @@ +#pragma once +#include "MotorSessionInfo.h" + +class FeedControl +{ +public: + enum class FeedMode + { + FMode_Low, + FMode_Mid, + FMode_High, + FMode_NOChange, + }; +public: + FeedControl(/* args */); + ~FeedControl(); + //设置搓纸模式匹配阈值 + void SetThre(double thre); + //获取预测搓纸模式 + FeedMode GetPredictFeedMode(); + //搓纸模式变更时 清除配置记录信息 + void ResetMode(); + //更新走纸流程相关信息 + void AppendPattern(MotorSessionInfo::MBTaskRecordInfo info); +private: + FeedMode calcFeedMode(); +private: + MotorSessionInfo m_sessioninfo; + double m_thre; +}; + diff --git a/device/gxx-linux/motorboard/Imotorboard.cpp b/device/gxx-linux/motorboard/Imotorboard.cpp deleted file mode 100644 index 134f59c..0000000 --- a/device/gxx-linux/motorboard/Imotorboard.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include "Imotorboard.h" -#include "PinMonitor.h" -#include "uartregsaccess.h" -#include -#include "stringex.hpp" -#include "config.h" -#include "StopWatch.h" -#include "applog.h" -#include "Capturer.h" - -IMotorBoard::IMotorBoard() : mb_ev_cb_(std::function()) -{} -IMotorBoard::~IMotorBoard(){ - -} diff --git a/device/gxx-linux/motorboard/Imotorboard.h b/device/gxx-linux/motorboard/Imotorboard.h deleted file mode 100644 index bf3b4fe..0000000 --- a/device/gxx-linux/motorboard/Imotorboard.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include "autoevent.hpp" -#include "commondef.h" -#include "Led.h" -#include "StopWatch.h" -#include "ThreadPool.h" - -class IRegsAccess; -class PinMonitor; -class Gpio; -class ICapturer; - -#include "../usb/src/common/packet.h" - - -class IMotorBoard{ -public: - IMotorBoard(); - virtual ~IMotorBoard(); - virtual void start() = 0; - virtual void stop() = 0; - virtual void clear_error() = 0; - virtual void pick_paper() = 0; - virtual void stop_pick_paper() = 0; - virtual int os_mode() = 0; - virtual bool paper_ready() = 0; - virtual bool is_converopen() = 0; - virtual bool is_scanning() = 0; - virtual bool is_jam() = 0; - virtual int paper_counter() = 0; - virtual bool set_long_paper(bool enable) = 0; - virtual bool set_double_inpect(bool enable) = 0; - virtual bool set_staple_inpect(bool enable) = 0; - virtual bool set_auto_paper(bool enable) = 0; - virtual bool set_color_mode(int mode) = 0; - virtual int get_speed_mode() = 0; - virtual bool set_speed_mode(int mode,int dpi,int iscolor) = 0; - virtual bool set_screw_inpect(bool enable) = 0; - virtual bool get_screw_inpect() = 0; - virtual bool set_screw_level(int level) = 0; - virtual int get_screw_level() = 0; - virtual bool wait_paper_out(int timeout_ms) = 0; - virtual bool wait_paper_in(int timeout_ms) = 0; - virtual bool read(unsigned int addr, unsigned int &val) = 0; - virtual bool write(unsigned int addr, unsigned int val) = 0; - virtual bool set_cuospeed(unsigned int speed,uint dpi,uint iscolor) = 0; - virtual void set_callbacks(MotorBoardGlue glue) = 0; - virtual bool get_keeplastpaper() = 0; - virtual std::shared_ptr regs() = 0; - virtual void set_capture(std::shared_ptr cap) = 0; - virtual void motor_reset() = 0; - virtual void LedControlOption(HG_LedOption option,uint32_t time) = 0; - virtual void clean_paper_road() = 0; - - void set_error(int value){ - mb_error = value; - } - void set_scancap(GScanCap cap) - { - m_scancap = cap; - } - void set_motorboard_event_callback(std::function cb) - { - mb_ev_cb_ = cb; - } - - static scanner_status scanner_status_from_raw(int raw) - { - switch(raw) - { - case 1: - return SCANNER_STATUS_PAPER_JAMMED; - case 2: - return SCANNER_STATUS_NO_PAPER; - case 4: - return SCANNER_STATUS_COVER_OPENNED; - case 0x20: - return SCANNER_STATUS_DOUBLE_FEEDED; - case 0x2000000: - return SCANNER_STATUS_PAPER_ON; - case 0x4000000: - return SCANNER_STATUS_COVER_CLOSED; - case 0: - default: - return SCANNER_STATUS_READY; // jam has resolved - } - } - -protected: - volatile int mb_error = 0; - GScanCap m_scancap; - - std::function mb_ev_cb_; -}; \ No newline at end of file diff --git a/device/gxx-linux/motorboard/Jtag.cpp b/device/gxx-linux/motorboard/Jtag.cpp new file mode 100644 index 0000000..aeab5e2 --- /dev/null +++ b/device/gxx-linux/motorboard/Jtag.cpp @@ -0,0 +1,95 @@ +#include "Jtag.h" + +Jtag::Jtag():jtag_tms(152),jtag_tck(156),jtag_tdi(155),jtag_tdo(72),COM_BOOT0(153) +{ + printf("Jtag()\n"); + char fname[128]; + + write_dev("/sys/class/gpio/export", 152); + write_dev("/sys/class/gpio/export", 156); + write_dev("/sys/class/gpio/export", 155); + write_dev("/sys/class/gpio/export", 72); + write_dev("/sys/class/gpio/export", 153); + + + jtag_tms.setDirection(Gpio::out); + jtag_tck.setDirection(Gpio::out); + jtag_tdi.setDirection(Gpio::out); + jtag_tdo.setDirection(Gpio::in); + COM_BOOT0.setDirection(Gpio::out); + + COM_BOOT0.setValue(Gpio::High); + jtag_tms.setValue(Gpio::Low); + jtag_tck.setValue(Gpio::Low); + jtag_tdi.setValue(Gpio::Low); + + +} + +void Jtag::TMS_Wr(u8 value) +{ + if(value == 1) + jtag_tms.setValue(Gpio::High); + else + jtag_tms.setValue(Gpio::Low); +} + +u8 Jtag::TMS_RD() +{ + return jtag_tms.getValue(); +} + +void Jtag::TCK_Wr(u8 value) +{ + if(value == 1) + jtag_tck.setValue(Gpio::High); + else + jtag_tck.setValue(Gpio::Low); +} + +u8 Jtag::TCK_RD() +{ + return jtag_tck.getValue(); +} + +void Jtag::TDI_Wr(u8 value) +{ + if(value == 1) + jtag_tdi.setValue(Gpio::High); + else + jtag_tdi.setValue(Gpio::Low); +} + +u8 Jtag::TDI_RD() +{ + return jtag_tdi.getValue(); +} + +u8 Jtag::TDO_RD() +{ + return jtag_tdo.getValue(); +} + +void Jtag::Anlogic_Calibration(void) +{ + /*Apply 2 pulses to TCK.*/ + TCK_Wr(1); + TCK_Wr(1); + TCK_Wr(0); + TCK_Wr(1); + TCK_Wr(0); + TCK_Wr(1); + TCK_Wr(1); + /*Delay for 1 millisecond. Pass on 1000 = 1ms delay.*/ + + Anlogic_ProcessRunTestTck(10000) ; + /*Apply 2 pulses to TCK*/ + TCK_Wr(1); + TCK_Wr(1); + TCK_Wr(0); + TCK_Wr(1); + TCK_Wr(0); + TCK_Wr(1); + TCK_Wr(1); + +} \ No newline at end of file diff --git a/device/gxx-linux/motorboard/Jtag.h b/device/gxx-linux/motorboard/Jtag.h new file mode 100644 index 0000000..05edc5d --- /dev/null +++ b/device/gxx-linux/motorboard/Jtag.h @@ -0,0 +1,41 @@ +#ifndef HGSCANSERVICE_JTAG_H +#define HGSCANSERVICE_JTAG_H + +#include +#include +#include +#include +#include +#include "DevUtil.h" +#include "Gpio.h" +#include +#include +#include + +extern void Anlogic_ProcessRunTestTck(int num); + +typedef unsigned int u32; +typedef unsigned char u8; + +class Jtag +{ +private: + Gpio jtag_tms; + Gpio jtag_tck; + Gpio jtag_tdi; + Gpio jtag_tdo; + Gpio COM_BOOT0; + +public: + Jtag(); + void TMS_Wr(u8 value); + u8 TMS_RD(); + void TCK_Wr(u8 value); + u8 TCK_RD(); + void TDI_Wr(u8 value); + u8 TDI_RD(); + u8 TDO_RD(); + void Anlogic_Calibration(void); +}; + +#endif \ No newline at end of file diff --git a/device/gxx-linux/motorboard/Led.cpp b/device/gxx-linux/motorboard/Led.cpp deleted file mode 100644 index 577fc41..0000000 --- a/device/gxx-linux/motorboard/Led.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "Led.h" - -#define LEDPATH "%s/%s/%s" - -std::string Led::timer = "timer"; -std::string Led::none = "none"; - -Led::Led(std::string name) { - path_brightness = string_format(LEDPATH, path_base.c_str(), name.c_str(), path_brightness.c_str()); - path_trigger = string_format(LEDPATH, path_base.c_str(), name.c_str(), path_trigger.c_str()); - path_delay_off = string_format(LEDPATH, path_base.c_str(), name.c_str(), path_delay_off.c_str()); - path_delay_on = string_format(LEDPATH, path_base.c_str(), name.c_str(), path_delay_on.c_str()); -} - -Led::~Led() { -} - -void Led::on(int time_ms) { - if (time_ms != 0) { - write_dev(path_trigger, timer); - write_dev(path_delay_off, time_ms); - write_dev(path_delay_on, time_ms); - } else { - //if (read_dev_s(path_trigger).find(none) == std::string::npos) - write_dev(path_trigger, none); - } - write_dev(path_brightness, 1); -} - -void Led::off() { - write_dev(path_brightness, 0); -} - -bool Led::isOn() { - return (bool)read_dev_i(path_brightness); -} - - -LedControl::LedControl():m_led_green(Led("green")),m_led_red(Led("red")),m_led_white(Led("white")){ -} -LedControl::~LedControl(){ - option(HG_LedOption::HG_OFF_ALL,0); -} - -HG_LedOption LedControl::get_state(){ - return m_state; -} -void LedControl::option(HG_LedOption option,uint32_t time){ - m_state = option; - switch (option) - { - case HG_LedOption::HG_OFF_ALL: - m_led_red.off(); - m_led_green.off(); - m_led_white.off(); - break; - case HG_LedOption::HG_ON_ALL: - m_led_green.on(time); - m_led_red.on(time); - m_led_white.on(time); - break; - case HG_LedOption::HG_RED_ON: - m_led_red.on(time); - m_led_green.off(); - m_led_white.off(); - break; - case HG_LedOption::HG_GREEN_ON: - m_led_green.on(time); - m_led_red.off(); - m_led_white.off(); - break; - case HG_LedOption::HG_WHITE_ON: - m_led_red.off(); - m_led_green.off(); - m_led_white.on(time); - break; - case HG_LedOption::HG_RED_WHITR_ON: - m_led_green.off(); - m_led_red.on(time); - m_led_white.on(time); - break; - case HG_LedOption::HG_RED_GREEN_ON: - m_led_red.on(time); - m_led_green.on(time); - m_led_white.off(); - break; - case HG_LedOption::HG_GREEN_WHITR_ON: - m_led_green.on(time); - m_led_red.off(); - m_led_white.on(time); - break; - default: - break; - } -} diff --git a/device/gxx-linux/motorboard/Led.h b/device/gxx-linux/motorboard/Led.h deleted file mode 100644 index 054ca82..0000000 --- a/device/gxx-linux/motorboard/Led.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include "DevUtil.h" -#include "stringex.hpp" - -enum HG_LedOption : uint8_t{ - HG_OFF_ALL = 0, - HG_RED_ON, - HG_GREEN_ON, - HG_WHITE_ON, - HG_RED_GREEN_ON, - HG_RED_WHITR_ON, - HG_GREEN_WHITR_ON, - HG_ON_ALL, -}; - -class Led -{ -public: - static std::string timer; - static std::string none; -public: - Led(std::string name); - ~Led(); - - void on(int time_ms = 0); - void off(); - bool isOn(); - -private: - const std::string path_base = "/sys/class/leds"; - std::string path_brightness = "brightness"; - std::string path_trigger = "trigger"; - std::string path_delay_off = "delay_off"; - std::string path_delay_on = "delay_on"; -}; - -class LedControl{ -public: - - LedControl(); - ~LedControl(); - void option(HG_LedOption option,uint32_t time = 0); - HG_LedOption get_state(); - -private: - Led m_led_red; - Led m_led_green; - Led m_led_white; - HG_LedOption m_state; -}; diff --git a/device/gxx-linux/motor_run/MotorConfig.cpp b/device/gxx-linux/motorboard/MotorConfig.cpp similarity index 81% rename from device/gxx-linux/motor_run/MotorConfig.cpp rename to device/gxx-linux/motorboard/MotorConfig.cpp index 102d038..b022ff2 100644 --- a/device/gxx-linux/motor_run/MotorConfig.cpp +++ b/device/gxx-linux/motorboard/MotorConfig.cpp @@ -23,12 +23,14 @@ std::string MotorConfig::GetParams(bool bzouzhi, MTBDType mttype) std::ifstream i(bzouzhi ? MT_TMC216_ZOU_PATH : MT_TMC216_CUO_PATH); i >> j; j_str = j.dump(); + i.close(); } else { std::ifstream i(bzouzhi ? MT_DRV888_ZOU_PATH : MT_DRV888_CUO_PATH); i >> j; j_str = j.dump(); + i.close(); } return j_str; } @@ -63,6 +65,7 @@ void MotorConfig::SetParams(bool bzouzhi, MTBDType mttype, MotorSpeedParamEx &pa ofstream ofs(path); ofs << std::setw(4) << j << std::endl; + ofs.close(); } std::vector MotorConfig::GetMotorSpeedParams(bool bzouzhi, MTBDType mttype) @@ -73,6 +76,7 @@ std::vector MotorConfig::GetMotorSpeedParams(bool bzouzhi, MT std::ifstream i(bzouzhi ? MT_TMC216_ZOU_PATH : MT_TMC216_CUO_PATH); json j; i >> j; + i.close(); for (json::iterator it = j.begin(); it != j.end(); ++it) { auto tmv = it.value(); @@ -86,6 +90,7 @@ std::vector MotorConfig::GetMotorSpeedParams(bool bzouzhi, MT std::ifstream i(bzouzhi ? MT_DRV888_ZOU_PATH : MT_DRV888_CUO_PATH); json j; i >> j; + i.close(); for (json::iterator it = j.begin(); it != j.end(); ++it) { auto tmv = it.value(); @@ -111,22 +116,21 @@ void MotorConfig::initconfigfile() MotorSpeedParamEx param; for (int k = 1; k < 4; k++) { - // //float ratio = k == 1 ? 1 : (k == 2 ? 1.51 : 2.81); - // param.mt_param.finalPeriod = s >= 2 ? 586500 / 4 : 586500; // s < 2 drv888 - // //param.mt_param.finalPeriod = s >= 2 ? 2000 / 4 : 2000; // s < 2 drv888 - // param.mt_param.Fmin = s >= 2 ? 1607750 / 4 : 1607750; - // param.mt_param.stepnum = 30; - // param.mt_param.a = 200; - // param.mt_param.offset = 7; - // param.mt_param.finalDelay = 2500; - // param.mt_param.acceleration_time = 2; - // param.speed = i; // 0 gray 1 color - // param.dpi = k; // 1 200dpi 2 300dpi 3 600dpi - // param.sp = 1200; + float ratio = k == 1 ? 1 : (k == 2 ? 1.51 : 2.81); + param.mt_param.finalPeriod = s >= 2 ? 2000 / 4 *ratio: 2000*ratio; // s < 2 drv888 + param.mt_param.finalPeriod = s >= 2 ? 2000 / 4 : 2000; // s < 2 drv888 + param.mt_param.Fmin = s >= 2 ? 80000 / 4 : 80000; + param.mt_param.stepnum = 0.5; + param.mt_param.a = 0.35; + param.mt_param.offset = -5.7; + param.mt_param.finalDelay = 2500; + param.mt_param.acceleration_time = 2; + param.speed = i; // 0 gray 1 color + param.dpi = k; // 1 200dpi 2 300dpi 3 600dpi + param.sp = 1200; for(int t = 0;t<2;t++) { - //param.colormode = t; - param = m_motor_params[s*30+(i-1)*6+(k-1)*2+t]; + param.colormode = t; json t_j; to_json(param, t_j); j.push_back(t_j); @@ -135,16 +139,12 @@ void MotorConfig::initconfigfile() } ofstream ofs(m_jsonpaths[s]); ofs << std::setw(4) << j << std::endl; + ofs.close(); } } } } -void MotorConfig::reset_json(){ - // for(int i =0;i MotorConfig::GetMotorSpeedParams(const std::string& json_str) { std::vector ret; diff --git a/device/gxx-linux/motorboard/MotorConfig.h b/device/gxx-linux/motorboard/MotorConfig.h new file mode 100644 index 0000000..7b87e55 --- /dev/null +++ b/device/gxx-linux/motorboard/MotorConfig.h @@ -0,0 +1,68 @@ +#pragma once +#include +#include "json.hpp" + +using json= nlohmann::json; + +struct MotorSpeedParam +{ + int finalPeriod; + int Fmin; + float stepnum; + float a; + float offset; + float finalDelay; + float acceleration_time; +}; + +struct MotorSpeedParamEx +{ + MotorSpeedParam mt_param; + int speed; + int colormode; + int dpi; + int sp; +}; + +#ifndef WIN32 +#define MT_DRV888_CUO_PATH "/usr/local/huago/drv888_cuo.json" +#define MT_DRV888_ZOU_PATH "/usr/local/huago/drv888_zou.json" +#define MT_TMC216_CUO_PATH "/usr/local/huago/tmc216_cuo.json" +#define MT_TMC216_ZOU_PATH "/usr/local/huago/tmc216_zou.json" +#else +#define MT_DRV888_CUO_PATH "drv888_cuo.json" +#define MT_DRV888_ZOU_PATH "drv888_zou.json" +#define MT_TMC216_CUO_PATH "tmc216_cuo.json" +#define MT_TMC216_ZOU_PATH "tmc216_zou.json" +#endif + +class MotorConfig +{ +private: + std::vector m_cuoParams; + std::vector m_zouParams; + const std::vector m_jsonpaths={ + MT_DRV888_CUO_PATH, + MT_DRV888_ZOU_PATH, + MT_TMC216_CUO_PATH, + MT_TMC216_ZOU_PATH + }; + +public: + enum class MTBDType + { + MT_TMC, + MT_DRV + }; + MotorConfig(/* args */); + ~MotorConfig(); + std::string GetParams(bool bzouzhi,MTBDType mttype); + void SetParams(bool bzouzhi,MTBDType mttype,MotorSpeedParamEx& param); + std::vector GetMotorSpeedParams(bool bzouzhi,MTBDType mttype); + std::vector GetMotorSpeedParams(const std::string& json_str); +private: + void initconfigfile(); + void to_json(MotorSpeedParamEx& param,json& j); + void from_json(json& j,MotorSpeedParamEx& param); +}; + diff --git a/device/gxx-linux/motorboard/MotorSessionInfo.cpp b/device/gxx-linux/motorboard/MotorSessionInfo.cpp new file mode 100644 index 0000000..20393cb --- /dev/null +++ b/device/gxx-linux/motorboard/MotorSessionInfo.cpp @@ -0,0 +1,117 @@ + +#include "MotorSessionInfo.h" +#include +#include +#include +#include +#include +#define MBTASKPATH "/usr/local/huago/mbtaskinfos.json" + +MotorSessionInfo::MotorSessionInfo(/* args */) : m_maxrecord(10) +{ +} + +MotorSessionInfo::~MotorSessionInfo() +{ +} + +//获取近十次的扫描情况汇总 +std::vector MotorSessionInfo::GetRecordInfo() +{ + + std::vector infos; + json j = getjsonobj(); + printf("\n -------------json = %s",j.dump().c_str()); + for (json::iterator it = j.begin(); it != j.end(); ++it) + { + auto tmv = it.value(); + MBTaskRecordInfo param; + js2struct(param, tmv); + infos.push_back(param); + } + //printf("\n -------------GetRecordInfo size"); + return infos; +} + +//仅记录最近十次的扫描情况,大于十次按照时间戳去除早前的记录 +void MotorSessionInfo::UpdateRecordInfo(MotorSessionInfo::MBTaskRecordInfo info) +{ + auto records = GetRecordInfo(); + //std::sort(records.begin(), records.end()); + printf("\n -------------GetRecordInfo size = %d",records.size()); + if (records.size() > 10) + { + records.pop_back(); + } + records.push_back(info); + savejsonobj(records); +} + +void MotorSessionInfo::RemoveInfos() +{ + std::lock_guard mutex(m_mutex); + system("rm -f /usr/local/huago/mbtaskinfos.json"); +} + +void MotorSessionInfo::js2struct(MotorSessionInfo::MBTaskRecordInfo &info, const json &j) +{ + j["CurrentScaned"].get_to(info.CurrentScaned); + j["DoubleFeed"].get_to(info.DoubleFeed); + j["FeedError"].get_to(info.FeedError); + j["Jammed"].get_to(info.Jammed); + j["NormalDone"].get_to(info.NormalDone); + j["TimeStampStart"].get_to(info.TimeStampStart); + j["TimeStampEnd"].get_to(info.TimeStampEnd); +} + +void MotorSessionInfo::struct2js(const MotorSessionInfo::MBTaskRecordInfo info, json &j) +{ + j["CurrentScaned"] = (info.CurrentScaned); + j["DoubleFeed"] = (info.DoubleFeed); + j["FeedError"] = (info.FeedError); + j["Jammed"] = (info.Jammed); + j["NormalDone"] = (info.NormalDone); + j["TimeStampStart"] = (info.TimeStampStart); + j["TimeStampEnd"] = (info.TimeStampEnd); +} + +json MotorSessionInfo::getjsonobj() +{ + std::lock_guard mutex(m_mutex); + struct stat buff; + json j; + if (stat(MBTASKPATH, &buff) == 0) //存在 + { + std::ifstream i(MBTASKPATH); + // std::string buf; + // buf.resize(buff.st_size); + // i.read(&buf[0],buff.st_size); + // j = json::parse(buf); + i >> j; + i.close(); + //printf("\n ----json = %s ",j.dump().c_str()); + } + return j; +} + + +void MotorSessionInfo::savejsonobj(std::vector infos) +{ + std::lock_guard mutex(m_mutex); + json j= json::array(); + printf("\n -------------infos size = %d",infos.size()); + for (size_t i = 0; i < infos.size(); i++) + { + json jitem; + struct2js(infos[i],jitem); + j.push_back(jitem); + } + + if(!j.empty()) + { + std::ofstream ofs(MBTASKPATH); + ofs << std::setw(4) << j << std::endl; + ofs.close(); + + } +} \ No newline at end of file diff --git a/device/gxx-linux/motorboard/MotorSessionInfo.h b/device/gxx-linux/motorboard/MotorSessionInfo.h new file mode 100644 index 0000000..ed4df00 --- /dev/null +++ b/device/gxx-linux/motorboard/MotorSessionInfo.h @@ -0,0 +1,54 @@ +#pragma once +#include +#include +#include + +using json = nlohmann::json; +class MotorSessionInfo +{ +public: + struct MBTaskRecordInfo + { + unsigned int CurrentScaned; + bool NormalDone; + bool Jammed; + bool DoubleFeed; + bool FeedError; + long TimeStampStart; + long TimeStampEnd; + bool operator < (const MBTaskRecordInfo& info) + { + return this->TimeStampEnd > info.TimeStampEnd; + } + + void Start() + { + std::chrono::time_point tpMicro = \ + std::chrono::time_point_cast(std::chrono::system_clock::now()); + this->TimeStampStart = tpMicro.time_since_epoch().count(); + } + + void Stop() + { + std::chrono::time_point tpMicro = \ + std::chrono::time_point_cast(std::chrono::system_clock::now()); + this->TimeStampEnd = tpMicro.time_since_epoch().count(); + } + }; + //nscanned / 300 nscanned∈[1,300] 即取值范围为[0,1.0] + +public: + MotorSessionInfo(/* args */); + ~MotorSessionInfo(); + std::vector GetRecordInfo();// m_mbtaskrecordInfos; + void UpdateRecordInfo(MBTaskRecordInfo info); + void RemoveInfos(); +private: + void js2struct(MBTaskRecordInfo& info,const json& j); + void struct2js(const MBTaskRecordInfo info,json& j); + json getjsonobj(); + void savejsonobj(std::vector infos); +private: + int m_maxrecord; + std::mutex m_mutex;//避免读写冲突 json文件丢失 +}; diff --git a/device/gxx-linux/motorboard/aje2vec.cpp b/device/gxx-linux/motorboard/aje2vec.cpp new file mode 100644 index 0000000..a8c20ae --- /dev/null +++ b/device/gxx-linux/motorboard/aje2vec.cpp @@ -0,0 +1,918 @@ +/******************************************************************* + * Copyright (c) 2011 -2021 Anlogic Inc. + * The Software is distributed in source code form and is open to + * re-distribution and modification where applicable +*******************************************************************/ + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include +#include + +#include "opcode.h" + +#define AJE_DEBUG + +/* jtag instruction macro list */ +#define INS_REFRESH 0x01 +#define INS_SAMPLE 0x05 +#define INS_READ_STATUS 0x20 +#define INS_BYPASS 0xFF + +#define INS_PROG_SPI 0x39 + +extern unsigned int g_hdr_size; +extern unsigned int g_hir_size; +extern unsigned int g_tdr_size; +extern unsigned int g_tir_size; + +extern unsigned char* g_hdr_data; +extern unsigned char* g_hir_data; +extern unsigned char* g_tdr_data; +extern unsigned char* g_tir_data; + +/* some static & global variables */ +static char s_compress = FULL_MODE; /* compress mode */ +static long int s_cfg_start_pos = 0; /* the start cfg position in aje file */ +static int s_done_status = 1; /* done pin status */ +static int s_find_refresh_ins = 0; /* the flag that refresh instrcution has been found or not */ +static int s_cur_level = 0; /* for daisy chain, current level */ +static int s_total_level = 0; /* for daisy chain, total level */ + +FILE* g_aje_file; +char g_aje_crc[3]; +long int g_freq = 0; +unsigned char s_idcode_pub = IDCODE_PUB; +static unsigned int s_cascade = 0; /* cascade flag */ + +/* function declared in decode.c */ +extern unsigned char* Anlogic_BytesDecode(long bytes); +extern unsigned char* Anlogic_NibbleDecode(long bytes); +extern unsigned char* Anlogic_HuffmanDecode(long bytes); +extern unsigned char* Anlogic_LzwDecode(long bytes); + +/* function declared in ajeutil.c */ +extern int Anlogic_GetBit(unsigned char* data, int id); +extern void Anlogic_SetBit(unsigned char* data, int id, int val); +extern char* Anlogic_HexStrToBinStr(char* src_str, int bin_len); + +/* function declared in vec.c */ +extern enum TAP_STATE Anlogic_TapState(unsigned char opcode); +extern const char* Anlogic_TapState2Str(enum TAP_STATE tap_state); +extern void Anlogic_SetEndDRState(enum TAP_STATE end_st); +extern void Anlogic_SetEndIRState(enum TAP_STATE end_st); +extern int Anlogic_TapTransist(enum TAP_STATE state); +extern int Anlogic_ExeSirCommand(unsigned char command, int cur_lvl, int total_lvl); +extern int Anlogic_ExeSdrCommand(unsigned int data_size, int cur_lvl, int total_lvl, + unsigned char* tdi_data, unsigned char* tdo_data); +extern void Anlogic_Init(void); +extern void Anlogic_ProcessRunTestTck(int num); +extern int Anlogic_SendData(unsigned char* tdi_data, unsigned int data_size, int cascade); +extern int Anlogic_SaveData(unsigned char* tdi_data, unsigned int data_size, unsigned char** tdo_data); +extern int Anlogic_ProcessShiftCmd(unsigned int op_code, unsigned int cascade, unsigned int read, unsigned int data_size, + unsigned char* tdi_data, unsigned char* tdo_data, unsigned char* mask); + +/* function forward declaration */ +int Anlogic_ExeSirCommands(unsigned int data_size, unsigned char* tdi_data, unsigned char* tdo_data, unsigned char* mask); +int Anlogic_ExeSDRCommands(unsigned int cascade, unsigned int data_size, + unsigned char* tdi_data, unsigned char* tdo_data, unsigned char* mask); + +long Anlogic_ReadNumber() +{ + long number = 0; + char byte = 0, cnt = 0; + do { + byte = fgetc(g_aje_file); + if (byte == EOF) { break; } + number += (byte & 0x007F) << (7 * cnt); + cnt ++; + } while (byte & 0x0080); + return number; +} + +unsigned long Anlogic_ProcessRuntestCmd() +{ + unsigned long ulTime = 0; + unsigned long num = 0; + char opcode = 0; + // char pre_opcode = 0; + char done = 0; + + if (g_freq == 0) { + g_freq = 80000; + } + + do { + //pre_opcode = opcode; + opcode = fgetc(g_aje_file); + switch (opcode) { + case TCK: + num = Anlogic_ReadNumber(); + if (num > 0x8000) { num -= 0x8000; } + ulTime += num; + ulTime -= 10; + break; + case WAIT: + num = Anlogic_ReadNumber(); + num -= 10; + if (num > 0x8000) { + num -= 0x8000; + num = g_freq * num / 1000; + } else { + num = g_freq * num / 1000000; + } + //if(TCK == pre_opcode){ + // ulTime = 0; + //} + ulTime += num; + break; + case RUNTEST: + break; + default: + done = 1; + break; + } + } while (!done); + + if (opcode == BEGINLINE) { + fseek(g_aje_file, -1, SEEK_CUR); + } + + //ulTime = 1200; + return ulTime; +} + +unsigned char* Anlogic_ProcessData(unsigned int byte_num) { + unsigned int index = 0; + unsigned char* data = NULL; + char mode = '\0'; + + if (s_compress == (char)FULL_MODE) { + data = (unsigned char*)calloc((byte_num+1), sizeof(unsigned char)); + for(index = 0; index < byte_num; ++index) { + data[index] = fgetc(g_aje_file); + } + } else { // compress mode + mode = fgetc(g_aje_file); + if (mode == 0) { // no compress + data = (unsigned char*)calloc((byte_num+1), sizeof(unsigned char)); + for(index = 0; index < byte_num; ++index) { + data[index] = fgetc(g_aje_file); + } + } else if (mode == 1) { // byte compress + data = Anlogic_BytesDecode(byte_num); + } else if (mode == 2) { // nibble compress + data = Anlogic_NibbleDecode(byte_num); + } else if (mode == 3) { // huffman compress + data = Anlogic_HuffmanDecode(byte_num); + } else if (mode == 4) { // LZW compress + data = Anlogic_LzwDecode(byte_num); + } else { + assert(0 && "Error: Unkown compress mode."); + } + } + return data; +} + +void Anlogic_PrintData(unsigned int byte_size, unsigned char* data) { + int byte_id = 0; + unsigned int bit_id = 0; + unsigned char byte = '\0'; + unsigned char flip_byte = '\0'; + + printf( " (" ); + for(byte_id = byte_size-1; byte_id >=0; --byte_id) { + byte = data[byte_id]; + flip_byte = 0x00; + for (bit_id = 0; bit_id < 8; bit_id++) { + flip_byte <<= 1; + if (byte & 0x1) { + flip_byte |= 0x1; + } + byte >>= 1; + } + printf("%02X", flip_byte); + } + printf(") "); +} + +/* Get the SIR Instruction */ +unsigned char Anlogic_ParseSirIns(unsigned int len, unsigned char* tdi_data) { + /* default value : bypass instruction */ + unsigned char sir_ins = INS_BYPASS; + + unsigned int byte_id = 0; + unsigned int bit_id = 0; + unsigned char byte = '\0'; + unsigned char flip_byte = '\0'; + + if (len % 8 != 0) { + return sir_ins; + } + + for(byte_id = 0; byte_id < len/8; ++byte_id) { + byte = tdi_data[byte_id]; + flip_byte = 0x00; + for (bit_id = 0; bit_id < 8; bit_id++) { + flip_byte <<= 1; + if (byte & 0x1) { + flip_byte |= 0x1; + } + byte >>= 1; + } + + if (flip_byte != INS_BYPASS) { + sir_ins = flip_byte; + break; + } + } + + return sir_ins; +} + +/* read the head and trailer bit number in sir instruction */ +int Anlogic_ReadSirInfo(int* header_num, int* trailer_num) { + unsigned int bin_num = 0; + unsigned int flip_byte = 0; + unsigned int bit_id = 0; + + int byte_id = 0; + int byte_num = 0; + + int* tmp_val = trailer_num; + + unsigned char* tdi = NULL; + char byte = '\0'; + + *header_num = 0; + *trailer_num = 0; + + bin_num = Anlogic_ReadNumber(); + byte_num = bin_num / 8; + if (bin_num % 8 != 0) { + byte_num++; + } + + if (fgetc(g_aje_file) != TDI) { + printf("Error Invalid format when executing read sir information!\n"); + fseek(g_aje_file, bin_num-1, SEEK_CUR); + return 0; + } + + tdi = Anlogic_ProcessData(byte_num); + for(byte_id = byte_num-1; byte_id >= 0; --byte_id) { + byte = tdi[byte_id]; + flip_byte = 0x00; + for (bit_id = 0; bit_id < 8; bit_id++) { + flip_byte <<= 1; + if (byte & 0x1) { + flip_byte |= 0x1; + } + byte >>= 1; + } + + if (flip_byte == BYPASS) { + *tmp_val += 1; + } else if (flip_byte != BYPASS) { + tmp_val = header_num; + if(flip_byte == IDCODE_PUB_2) { + s_idcode_pub = IDCODE_PUB_2; + } + } + } + + if (CONTINUE != fgetc(g_aje_file)) { + printf("Error Invalid format when executing read sir information!\n"); + return 0; + } + + return (tmp_val == trailer_num) ? 0 : 1; +} + +int Anlogic_ProcessShiftCommand(char op_code) +{ + int rtn_val = AJE_OK; + int id = 0; + unsigned int bin_num = 0; + unsigned int byte_num = 0; + unsigned char* tdi = NULL; + unsigned char* tdo = NULL; + unsigned char* msk = NULL; + unsigned char ins = 0xFF; + char byte = '\0'; + + bin_num = Anlogic_ReadNumber(); + byte_num = bin_num / 8; + if (bin_num % 8 != 0) { + byte_num++; + } + + while((byte = fgetc(g_aje_file)) != CONTINUE) { + switch (byte) { + case TDI: + tdi = Anlogic_ProcessData(byte_num); + break; + case TDO: + tdo = Anlogic_ProcessData(byte_num); + break; + case MASK: + msk = Anlogic_ProcessData(byte_num); + break; + default: + printf("Error: Invalid format when executing process sir or sdr instruction!\n"); + return AJE_INVALID_COMMAND; + break; + } + } + + /* exe sir or sdr instruction */ + if (op_code == SIR) { + + /* if done=0, 'refresh' must be executed before 'program_spi' */ + if (s_done_status == 0 && s_find_refresh_ins == 0) { + ins = Anlogic_ParseSirIns(bin_num, tdi); + if (ins == INS_REFRESH) { + s_find_refresh_ins = 1; + } else if (ins == INS_PROG_SPI) { +#ifdef AJE_DEBUG + printf("SIR %d TDI (", s_total_level*8); + for (id = 1; id <= s_total_level; ++id) { + if (id == s_cur_level) { + printf("%02X", INS_REFRESH); + } else { + printf("FF"); + } + } + printf(") ;\n"); + printf("SIR %d TDI (", s_total_level*8); + + for (id = 1; id <= s_total_level; ++id) { + printf("FF"); + } + printf(") ;\n"); +#endif + Anlogic_ExeSirCommand(INS_REFRESH, s_cur_level, s_total_level); + Anlogic_ExeSirCommand(INS_BYPASS, s_cur_level, s_total_level); + s_done_status = 1; + } + } + +#ifdef AJE_DEBUG + printf("SIR %d TDI", bin_num); + Anlogic_PrintData(byte_num, tdi); + if (tdo != NULL) { + printf("TDO"); + Anlogic_PrintData(byte_num, tdo); + } + if (msk != NULL) { + printf("MASK"); + Anlogic_PrintData(byte_num, msk); + } + printf(";\n"); +#endif + + rtn_val = Anlogic_ExeSirCommands(bin_num, tdi, tdo, msk); + } else { + +#ifdef AJE_DEBUG + printf("SDR %d TDI", bin_num); + Anlogic_PrintData(byte_num, tdi); + if (tdo != NULL) { + printf("TDO"); + Anlogic_PrintData(byte_num, tdo); + } + if (msk != NULL) { + printf("MASK"); + Anlogic_PrintData(byte_num, msk); + } + printf(";\n"); +#endif + + rtn_val = Anlogic_ExeSDRCommands(s_cascade, bin_num, tdi, tdo, msk); + } + + //free tdi tdo msk + if (tdi != NULL) { free(tdi); tdi = NULL; } + if (tdo != NULL) { free(tdo); tdo = NULL; } + if (msk != NULL) { free(msk); msk = NULL; } + + return rtn_val; +} + +int Anlogic_ProcessBypassCommand(char op_code) { + unsigned int bin_num = 0; + unsigned int byte_num = 0; + unsigned int index = 0; + + unsigned char* tdi = NULL; + char byte = '\0'; + + char* op_code_str = NULL; + + bin_num = Anlogic_ReadNumber(); + if (bin_num > 0) { + byte_num = bin_num / 8; + if (bin_num % 8 != 0) { + byte_num++; + } + byte = fgetc(g_aje_file); + if (byte == TDI) { + tdi = (unsigned char*)calloc((byte_num+1), sizeof(unsigned char)); + for(index = 0; index < byte_num; ++index) { + tdi[index] = fgetc(g_aje_file); + } + } + } + + switch (op_code) + { + case TIR: op_code_str = "TIR"; g_tir_size = bin_num; g_tir_data = tdi; break; + case TDR: op_code_str = "TDR"; g_tdr_size = bin_num; g_tdr_data = tdi; break; + case HIR: op_code_str = "HIR"; g_hir_size = bin_num; g_hir_data = tdi; break; + case HDR: op_code_str = "HDR"; g_hdr_size = bin_num; g_hdr_data = tdi; break; + default: + printf("Error: invalid Head/Trailer format, unkown opcode.\n\n"); + return AJE_INVALID_COMMAND; + } + +#ifdef AJE_DEBUG + printf("%s %d", op_code_str, bin_num); + if ( bin_num > 0) { + printf(" TDI "); + Anlogic_PrintData(byte_num, tdi); + } + printf(" ;\n"); +#endif + + if (bin_num > 0) { // Skip CONTINUE command + fgetc(g_aje_file); + } + return AJE_OK; +} + +int Anlogic_ExeSirCommands(unsigned int data_size, unsigned char* tdi_data, unsigned char* tdo_data, + unsigned char* mask) { + unsigned int rtn_val = AJE_OK; + unsigned int op_code = SIR; + unsigned int cascade = 0; // no casecade + unsigned int read = 0; // send data only + rtn_val = Anlogic_ProcessShiftCmd(op_code, cascade, read, data_size, tdi_data, tdo_data, mask); + return rtn_val; +} + +int Anlogic_ExeSDRCommands(unsigned int cascade, unsigned int data_size, + unsigned char* tdi_data, unsigned char* tdo_data, unsigned char* mask) { + unsigned int rtn_val = AJE_OK; + unsigned int op_code = SDR; + unsigned int read = 0; // send data only + rtn_val = Anlogic_ProcessShiftCmd(op_code, cascade, read, data_size, tdi_data, tdo_data, mask); + return rtn_val; +} + +/* + * read the aje header information, + * include crc, version, compress mode, maximum memory size and vendor +*/ +int Anlogic_ReadAjeHeader() +{ + char byte; + char buffer[100]; + int i; + printf("Anlogic_ReadAjeHeader start.\n"); + // crc bytes + if (fgetc(g_aje_file) != FILECRC) { + return AJE_FILE_INVALID; + } + + if (fgets(g_aje_crc, 3, g_aje_file) == NULL) { + return AJE_FILE_INVALID; + } + else { + printf("g_aje_crc[0] = 0x%02x, g_aje_crc[1] = 0x%02x, g_aje_crc[2] = 0x%02x,\n", + g_aje_crc[0],g_aje_crc[1],g_aje_crc[2]); + } + + // version + if (fgets(buffer, 9, g_aje_file) == NULL) { + return AJE_FILE_INVALID; + } + else + { + for(int i=0;i<9;i++) + printf("buffer[%d] = 0x%02x ",i,buffer[i]); + printf("\n"); + } + + // compress or full + byte = fgetc(g_aje_file); + if (byte != (char)COMP_MODE && byte != (char)FULL_MODE) { + return AJE_FILE_INVALID; + } + else + printf("byte = 0x%02x ",byte); + s_compress = byte; + + // maximum memory size + if (MEM != fgetc(g_aje_file)) { + return AJE_FILE_INVALID; + } + Anlogic_ReadNumber(); + + // Vender + if (VENDOR != fgetc(g_aje_file )) { + return AJE_FILE_INVALID; + } + if (ANLOGIC != fgetc(g_aje_file)) {; + return AJE_FILE_INVALID; + } + + s_cfg_start_pos = ftell(g_aje_file); + + printf("Anlogic_ReadAjeHeader end.\n"); + + return AJE_OK; +} + +/* read the chip id before processing data, need to get the chain information */ +int Anlogic_ReadChipIdcode(void) +{ + int rtn_val = AJE_OK; + int finish = 0; + + /* get from HDR/TDR Command */ + int hdr_num = 0; + int tdr_num = 0; + + /* get from SIR Command */ + int trailer_num = 0; + int header_num = 0; + + long line_length = 0; + char op_code = 0x00; + + printf("Anlogic_ReadChipIdcode start.\n"); + while((finish == 0) && (fgetc(g_aje_file)) == BEGINLINE) { + line_length = Anlogic_ReadNumber()/8; + printf("Anlogic_ReadNumber()/8 = %d.\n",line_length); + op_code = fgetc(g_aje_file); + printf("op_code = 0x%02x.\n",op_code); + switch (op_code) { + case HDR: + printf("Acase HDR.\n"); + hdr_num = Anlogic_ReadNumber(); + if (hdr_num != 0) { + while (CONTINUE != fgetc(g_aje_file)); + } + break; + case TDR: + printf("Acase TDR.\n"); + tdr_num = Anlogic_ReadNumber(); + if (tdr_num != 0) { + while (CONTINUE != fgetc(g_aje_file)); + } + break; + case SIR: + printf("Acase SIR.\n"); + finish = Anlogic_ReadSirInfo(&header_num, &trailer_num); + break; + default: + printf("Acase default.\n"); + fseek(g_aje_file, line_length-1, SEEK_CUR); + break; + } + } + + if (finish == 0) { + return AJE_WARNING; + } + + s_cur_level = tdr_num+trailer_num+1; + s_total_level = tdr_num+trailer_num+1+header_num+hdr_num; + + rtn_val = Anlogic_ExeSirCommand(s_idcode_pub, s_cur_level, s_total_level); + if (rtn_val != AJE_OK) { + return rtn_val; + } + + unsigned char* tdo_data = (unsigned char*)malloc(5*sizeof(unsigned char)); + tdo_data[4] = '\0'; + rtn_val = Anlogic_ExeSdrCommand(32, s_cur_level, s_total_level, NULL, tdo_data); + if (rtn_val == AJE_OK) { /* print 32 bit chip id in terminal */ + if (tdo_data[0] == 0 && tdo_data[1] == 0 && + tdo_data[2] == 0 && tdo_data[3] == 0) { + printf("Error: Chip validation failed, please check the connection.\n"); + rtn_val = AJE_ERROR; + } else { + printf("\n Chip Id : "); + Anlogic_PrintData(4, tdo_data); + printf("\n"); + } + } + free(tdo_data); + tdo_data = NULL; + printf("Anlogic_ReadChipIdcode end.\n"); + return rtn_val; +} + +/* Loading Read chip io status instrcution and compare ref_io_status */ +int Anlogic_LoadingReadChipIOStatusInstruction(unsigned int bit_size, unsigned char* ref_io_status) { + int rtn_val = AJE_OK; + int bit = 0; + unsigned int io_index = 0; + unsigned int byte = (bit_size+7)/8; + + rtn_val = Anlogic_ExeSirCommand(SAMPLE, s_cur_level, s_total_level); + if (rtn_val != AJE_OK) { + return rtn_val; + } + + unsigned char* tdo_data = (unsigned char*)malloc((byte+1)*sizeof(unsigned char)); + tdo_data[byte] = '\0'; + rtn_val = Anlogic_ExeSdrCommand(bit_size, s_cur_level, s_total_level, NULL, tdo_data); + if (rtn_val == AJE_OK) { + printf("\nIO Status: \n"); + printf("Bs order\t\tRef\t\tRead\t\tVerify\n"); + + for (io_index = 0; io_index < bit_size; ++io_index) { + bit = Anlogic_GetBit(tdo_data, io_index); + printf("%8d\t\t%c\t\t%d\t\t", io_index, ref_io_status[io_index], bit); + if (ref_io_status[io_index] - '0' == bit) { + printf("true\n"); + } else { + printf("false\n"); + } + } + } + + free(tdo_data); + tdo_data = NULL; + return rtn_val; +} + +int Anlogic_ReadChipIOStatus(char* io_state_file) { + int rtn_val = AJE_OK; + FILE* io_stat_stream = NULL; + char line[LINE_MAX_SIZE]; + char buf[10]; + int sscanf_num = 0; + char sdr_tdi_str[DATA_MAX_SIZE]; + char sdr_tdo_str[DATA_MAX_SIZE]; + char sdr_mask_str[DATA_MAX_SIZE]; + + char* sdr_tdo_bin_str = NULL; + char* sdr_mask_bin_str = NULL; + unsigned char* ref_io_status = NULL; + + int sir_num = 0; + int sir_val = 0; + int sdr_num = 0; + int str_idx = 0; + + int find_sample_ins = 0; /* sample instruction flag */ + + char* p = strstr(io_state_file, ".svf"); + if (p == NULL || strcmp(p, ".svf") != 0) { + printf("Error: %s is not a svf file\n", io_state_file); + return AJE_FILE_INVALID; + } + + if ((io_stat_stream = fopen(io_state_file, "r")) == NULL) { + printf("Error: cannot read the svf file %s\n", io_state_file); + return AJE_FILE_OPEN_FAIL; + } + + // Parse svf file + while (!feof(io_stat_stream)) { + fgets(line, LINE_MAX_SIZE, io_stat_stream); + + // Find "Sample" instruction, E.G. SIR 8 TDI (05) + if (find_sample_ins == 0) { + sscanf_num = sscanf(line, "SIR %d TDI (%d)", &sir_num, &sir_val); + if (sscanf_num != 2) { continue; } + if (sir_num != 8 || sir_val != INS_SAMPLE) { + continue; + } + find_sample_ins = 1; + } else { + if (strncasecmp(line, "SDR", 3) != 0) { + continue; + } + // sample instruction + // E.G. SDR 426 TDI (3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + // TDO (3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBAFBFEAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + // MASK (0000000000000000000000000000000000000000000000AAAAAAAA00000000000000000000000000000000000000000000000000000); + sscanf_num = sscanf(line, "SDR %d TDI (%[^)]) TDO (%[^)]) MASK (%[^)])", &sdr_num, sdr_tdi_str, sdr_tdo_str, sdr_mask_str); + if (sscanf_num == 2) { // for line feeds + fgets(line, LINE_MAX_SIZE, io_stat_stream); + sscanf_num = sscanf(line, "%s (%[^)])", buf, sdr_tdo_str); + assert(strcasecmp(buf, "TDO") == 0); + if (sscanf_num == 2) { + fgets(line, LINE_MAX_SIZE, io_stat_stream); + sscanf_num = sscanf(line, "%s (%[^ )])", buf, sdr_mask_str); + assert(strcasecmp(buf, "MASK") == 0); + } + } + + if (sdr_num == 0 || sdr_tdi_str == NULL || sdr_tdo_str == NULL || sdr_mask_str == NULL) { + printf("Error: Invalid SDR string %s", line); + return AJE_FILE_INVALID; + } + + ref_io_status = (unsigned char*)malloc((sdr_num+1)*sizeof(unsigned char)); + memset(ref_io_status, 'x', sdr_num); + ref_io_status[sdr_num] = 0x00; + + sdr_tdo_bin_str = Anlogic_HexStrToBinStr(sdr_tdo_str, sdr_num); + sdr_mask_bin_str = Anlogic_HexStrToBinStr(sdr_mask_str, sdr_num); + + for(str_idx = 0; str_idx < sdr_num; ++str_idx) { + if (sdr_mask_bin_str[str_idx] == '1') { // the bit need verify + ref_io_status[sdr_num-1-str_idx] = sdr_tdo_bin_str[str_idx]; + } + } + } // end read sdr instruction + } // end of read file + + if (ref_io_status == NULL) { + printf("Error: Invalid svf file %s, cannot find the sample data", io_state_file); + return AJE_FILE_INVALID; + } + + if (sdr_tdo_bin_str != NULL) { free(sdr_tdo_bin_str); sdr_tdo_bin_str = NULL; } + if (sdr_mask_bin_str != NULL) { free(sdr_mask_bin_str); sdr_mask_bin_str = NULL; } + + rtn_val = Anlogic_LoadingReadChipIOStatusInstruction(sdr_num, ref_io_status); + + return rtn_val; +} + +int Anlogic_CheckDonePinStatus() { + int rtn_val = AJE_OK; + unsigned char* tdo_data = NULL; + + s_done_status = 1; + rtn_val = Anlogic_ExeSirCommand(INS_READ_STATUS, s_cur_level, s_total_level); + + tdo_data = (unsigned char*)malloc(5*sizeof(unsigned char)); + tdo_data[4] = '\0'; + rtn_val = Anlogic_ExeSdrCommand(32, s_cur_level, s_total_level, NULL, tdo_data); + if (rtn_val == AJE_OK) { + s_done_status = Anlogic_GetBit(tdo_data, 26); + } + + free(tdo_data); + tdo_data = NULL; + return rtn_val; +} + +/* core function, parse aje file and process data */ +int Anlogic_ProcessCmd() { + int rtn_val = AJE_OK; + int tck_num = 0; /* for runtest num tck command */ + int loop_num = 0; /* for loop command */ + long cmd_length = 0; + long cur_pos = 0; + long freq = 0; + char op_code = '\0'; + + enum TAP_STATE tap_state = TAP_RESET; + + fseek(g_aje_file, s_cfg_start_pos, SEEK_SET); /* restore to the start position of configuration */ + + while((fgetc(g_aje_file)) == BEGINLINE) { + cmd_length = Anlogic_ReadNumber()/8; + + op_code = fgetc(g_aje_file); + switch (op_code) { + case STATE: + tap_state = Anlogic_TapState(fgetc(g_aje_file)); + Anlogic_TapTransist(tap_state); + if (cmd_length == 2) { + printf("STATE %s;\n", Anlogic_TapState2Str(tap_state)); + } + if (cmd_length >= 2 && tap_state == TAP_IDLE) { + tck_num = Anlogic_ProcessRuntestCmd(); + if (tck_num > 0) { + Anlogic_ProcessRunTestTck(tck_num); + } + } + break; + case FREQUENCY: + freq = Anlogic_ReadNumber(); + if (g_freq == 0 || g_freq > freq) { + g_freq = freq; +#ifdef AJE_DEBUG + printf("FREQUENCY %.2E HZ;\n", (float)g_freq); +#endif + } + break; + case SIR: + case SDR: + rtn_val = Anlogic_ProcessShiftCommand(op_code); + break; + case LOOP: + loop_num = Anlogic_ReadNumber(); + cur_pos = ftell(g_aje_file); + break; + case ENDLOOP: + if (loop_num > 1) { + fseek(g_aje_file, cur_pos, SEEK_SET); + loop_num--; + } + break; + case TDR: + case TIR: + case HDR: + case HIR: + rtn_val = Anlogic_ProcessBypassCommand(op_code); + break; + case ENDIR: + tap_state = Anlogic_TapState(fgetc(g_aje_file)); + Anlogic_SetEndIRState(tap_state); + break; + case ENDDR: + tap_state = Anlogic_TapState(fgetc(g_aje_file)); + Anlogic_SetEndDRState(tap_state); + break; + case SETFLOW: + if (fgetc(g_aje_file) == CASCADE) { + s_cascade = 1; + } + break; + case RESETFLOW: + if (fgetc(g_aje_file) == CASCADE) { + s_cascade = 0; + } + break; + case TRST: + if (fgetc(g_aje_file) == ON) { + printf("TRST ON;\n"); + } else { + printf("TRST OFF;\n"); + } + break; + case RUNTEST: + { + fseek(g_aje_file, cmd_length-1, SEEK_CUR); + } + break; + default: + printf("Error: invalid file format, unkown opcode.\n\n"); + return AJE_INVALID_COMMAND; + } + + if (rtn_val != AJE_OK) { + return rtn_val; + } + } + return rtn_val; +} + + +int Anlogic_AjeToVec(const char* aje_file) { + int rtn_code = AJE_OK; + char* io_state_file = NULL; /* input svf file, use to read io status */ + + if ((g_aje_file = fopen(aje_file, "rb")) == NULL) { + return AJE_FILE_OPEN_FAIL; + } + else + printf("fopen %s sucess,file * = %p.\n",aje_file,g_aje_file); + + /* read header content */ + rtn_code = Anlogic_ReadAjeHeader(); + if (rtn_code != AJE_OK) { + return rtn_code; + } + + /* execute "state reset" first, 2019/12/20 */ + Anlogic_Init(); + + /* read chip id code */ + rtn_code = Anlogic_ReadChipIdcode(); + if (rtn_code != AJE_OK) { + return rtn_code; + } + + /* read io status */ + if (io_state_file != NULL) { + rtn_code = Anlogic_ReadChipIOStatus(io_state_file); + if (rtn_code != AJE_OK) { + return rtn_code; + } + } + + /* check done pin status */ + Anlogic_CheckDonePinStatus(); + + /* core process function */ + rtn_code = Anlogic_ProcessCmd(); + + fclose(g_aje_file); + return rtn_code; +} diff --git a/device/gxx-linux/motorboard/ajeutil.cpp b/device/gxx-linux/motorboard/ajeutil.cpp new file mode 100644 index 0000000..0cb7cc3 --- /dev/null +++ b/device/gxx-linux/motorboard/ajeutil.cpp @@ -0,0 +1,101 @@ +/******************************************************************* +* Copyright (c) 2011 -2021 Anlogic Inc. + * The Software is distributed in source code form and is open to + * re-distribution and modification where applicable +*******************************************************************/ + +/******************************************************************* + Filename : ajeutil.c + Description: utility source file + Log: initial version, December 2019 +*******************************************************************/ + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include + +int Anlogic_GetBit(unsigned char* data, int id) { + return (data[id/8] & (1 << (7-id%8))) ? 1 : 0; +} + +void Anlogic_SetBit(unsigned char* data, int id, int val) { + unsigned char mask = 1 << (7-id%8); + if (val) { + data[id/8] |= mask; + } else { + data[id/8] &= ~mask; + } +} + +/* reverse char data e.g. 8'b10001101 -> 8'b10110001 */ +unsigned char Anlogic_ReverseChar(unsigned char byte) { + unsigned int bit_id = 0; + unsigned char flip_byte = 0x00; + for (bit_id = 0; bit_id < 8; ++bit_id) { + flip_byte <<= 1; + if (byte & 0x1) { + flip_byte |= 0x1; + } + byte >>= 1; + } + return flip_byte; +} + +/* tranfer hex to bin data, e.g. char('A') -> char[4] = {'1', '0', '1', '0' } */ +void Anlogic_HexTobin(char hex, char* char_s) { + switch(hex) { + case '0': strcpy(char_s ,"0000"); break; + case '1': strcpy(char_s ,"0001"); break; + case '2': strcpy(char_s ,"0010"); break; + case '3': strcpy(char_s ,"0011"); break; + case '4': strcpy(char_s ,"0100"); break; + case '5': strcpy(char_s ,"0101"); break; + case '6': strcpy(char_s ,"0110"); break; + case '7': strcpy(char_s ,"0111"); break; + case '8': strcpy(char_s ,"1000"); break; + case '9': strcpy(char_s ,"1001"); break; + case 'a': + case 'A': strcpy(char_s ,"1010"); break; + case 'b': + case 'B': strcpy(char_s ,"1011"); break; + case 'c': + case 'C': strcpy(char_s ,"1100"); break; + case 'd': + case 'D': strcpy(char_s ,"1101"); break; + case 'e': + case 'E': strcpy(char_s ,"1110"); break; + case 'f': + case 'F': strcpy(char_s ,"1111"); break; + default: + printf("Error: HexToChar Invalid Hex value %c", hex); + } +} + +char* Anlogic_HexStrToBinStr(char* src_str, int bin_len) { + char* bin_value = NULL; + int hex_idx = 0; + int char_idx = 0; + char char_s[5] = { 0 }; + int hex_size = strlen(src_str); + if (hex_size*4 < bin_len) { + return NULL; + } + bin_value = (char*)malloc((bin_len+1)*sizeof(char)); + bin_value[bin_len] = 0x00; + + for(hex_idx=hex_size-1; hex_idx>=0; --hex_idx) { + char c = src_str[hex_idx]; + Anlogic_HexTobin(c, char_s); + for (char_idx = 0; char_idx<4; ++char_idx) { + bin_value[--bin_len] = char_s[3-char_idx]; + if (bin_len == 0) { + return bin_value; + } + } // end char_idx + } // end hex_idx + return bin_value; +} + diff --git a/device/gxx-linux/motorboard/decodel.cpp b/device/gxx-linux/motorboard/decodel.cpp new file mode 100644 index 0000000..c93a6d0 --- /dev/null +++ b/device/gxx-linux/motorboard/decodel.cpp @@ -0,0 +1,155 @@ +/******************************************************************* +* Copyright (c) 2011 -2021 Anlogic Inc. + * The Software is distributed in source code form and is open to + * re-distribution and modification where applicable +*******************************************************************/ + +/*********************************************************************** +Filename: decode.c +Description: decode the data from aje file +Log: initial version, July 2019 + ***********************************************************************/ + +#include +#include +#include + +extern FILE* g_aje_file; + +/* Function delcared in lzw_lib.c */ +extern int lzw_decompress (void (*dst)(int), int (*src)(void)); + +unsigned char* g_pWriteBuffer = NULL; +long int g_iWriteCount = 0; + +void Anlogic_WriteBufferByte(int byte) +{ + g_pWriteBuffer[g_iWriteCount++] = (unsigned char)byte; +} + +int Anlogic_ReadAjeByte(void) +{ + return fgetc(g_aje_file); +} + +long Anlogic_NumberDecode(void) { + long number = 0; + char byte = '\0'; + unsigned int count = 0; + do { + byte = fgetc(g_aje_file); + number += (byte & 0x7F) << (7 * count++); + } while (byte & 0x80); + return number; +} + +unsigned char* Anlogic_BytesDecode(long bytes) { + long int i = 0; + long int key_count = 0; + unsigned char byte = 0, key = 0; + unsigned char* rtn_val = NULL; + rtn_val = (unsigned char*)malloc((bytes+1)*sizeof(unsigned char)); + + key = fgetc(g_aje_file); + + for (i = 0; i < bytes; i++) { + if (key_count <= 0) { + byte = fgetc(g_aje_file); + rtn_val[i] = byte; + if (byte == key) { + key_count = Anlogic_NumberDecode(); // The number of key bytes + } + } else { + key_count--; // Use up the key chain first + rtn_val[i] = key; + } + } + return rtn_val; +} + +unsigned char* Anlogic_NibbleDecode(long bytes) { + int i = 0, j = 0, byte_time = 0; + long int num_keys = 0, key_bytes, key_times; + unsigned char *buffer = 0; + unsigned char* rtn_val; + rtn_val = (unsigned char*)malloc((bytes+1)*sizeof(unsigned char)); + + num_keys = Anlogic_NumberDecode(); + key_bytes = (num_keys + 1) / 2; + key_times = (bytes * 2) / num_keys; + buffer = (unsigned char*)calloc(key_bytes + 1 , sizeof(unsigned char)); + if (!buffer) { + assert(0 && "nibble decode: calloc fail"); + } + + for (i = 0; i < key_bytes; i++ ) + buffer[i] = fgetc(g_aje_file); + + if (num_keys % 2 == 0) { + for ( i = 0; i < key_times; i++ ) { + for ( j = 0; j < key_bytes; j++ ) { + rtn_val[j+i*key_bytes] = buffer[j]; + } + } + } else { + assert(key_times % 2 == 0); + buffer = (unsigned char*)realloc(buffer, key_bytes*2*sizeof(unsigned char)); + if (!buffer) { + assert(0 && "nibble decode: realloc fail"); + } + //buffer[key_bytes-2 : 0] keep no change + for(i = key_bytes-1; i < key_bytes*2-1; ++i) { + if (i == key_bytes-1) + buffer[i] = (buffer[i] & 0xF0) + (buffer[0] >> 4); + else + buffer[i] = ((buffer[i-key_bytes] << 4) & 0xF0) + + (buffer[i-key_bytes+1] >> 4); + } + byte_time = key_times / 2; + for(i = 0; i < byte_time; ++i) { + for(j = 0; j < (key_bytes*2-1); ++j) { + rtn_val[j+i*(key_bytes*2-1)] = buffer[j]; + } + } + } + return rtn_val; +} + +unsigned char* Anlogic_HuffmanDecode(long bytes) { + int i = 0, j = 0, m = 0, bits = 8; + unsigned char cur_char = 0, key = 0, byte = 0; + unsigned char* rtn_val; + rtn_val = (unsigned char*)malloc((bytes+1)*sizeof(unsigned char)); + + key = fgetc(g_aje_file); + + for ( i = 0; i < bytes; i++ ) { + byte = 0x00; + if ( bits > 7 ) { + cur_char = fgetc(g_aje_file); + bits = 0; + } + if ( ( cur_char << bits++ ) & 0x80 ) { + m = 8; + for (j = 0; j < m; j++) { + if (bits > 7) { + cur_char = fgetc(g_aje_file); + bits = 0; + } + byte |= ( ( cur_char << bits++ ) & 0x80 ) >> j; + } + } else { + byte = key; + m = 0; + } + rtn_val[i] = byte; + } + return rtn_val; +} + +unsigned char* Anlogic_LzwDecode(long bytes) { + g_pWriteBuffer = (unsigned char*)malloc((bytes+1)*sizeof(unsigned char)); + g_iWriteCount = 0; + lzw_decompress(Anlogic_WriteBufferByte, Anlogic_ReadAjeByte); + return g_pWriteBuffer; +} diff --git a/device/gxx-linux/motorboard/jtagupdata.cpp b/device/gxx-linux/motorboard/jtagupdata.cpp new file mode 100644 index 0000000..a65a07d --- /dev/null +++ b/device/gxx-linux/motorboard/jtagupdata.cpp @@ -0,0 +1,26 @@ +#include "jtagupdata.h" +#include "aje2vec.cpp" +JtagUp::JtagUp(std::string file):filepath(file){ + m_state = 0; +} +JtagUp::~JtagUp(){ + if(is_uping()) + m_fu.get(); +} +void JtagUp::startup(){ + if(is_uping()) + return; + m_state = 0; + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + m_fu = std::async(std::launch::async,&JtagUp::upfc,this); +} +bool JtagUp::is_uping() +{ + return m_fu.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout; +} +int JtagUp::getresult(){ + return m_state; +} +void JtagUp::upfc(){ + m_state = Anlogic_AjeToVec(filepath.c_str()); +} \ No newline at end of file diff --git a/device/gxx-linux/motorboard/jtagupdata.h b/device/gxx-linux/motorboard/jtagupdata.h new file mode 100644 index 0000000..aec9287 --- /dev/null +++ b/device/gxx-linux/motorboard/jtagupdata.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include +#include "Jtag.h" +#include "opcode.h" +#include +#include + +class JtagUp{ +public: + JtagUp(std::string file); + ~JtagUp(); + void startup(); + bool is_uping(); + int getresult(); +private: + void upfc(); + volatile int m_state; + std::future m_fu; + std::string filepath; +}; \ No newline at end of file diff --git a/device/gxx-linux/motorboard/lzw_lib.cpp b/device/gxx-linux/motorboard/lzw_lib.cpp new file mode 100644 index 0000000..cf3701a --- /dev/null +++ b/device/gxx-linux/motorboard/lzw_lib.cpp @@ -0,0 +1,353 @@ +//////////////////////////////////////////////////////////////////////////// +// **** LZW-AB **** // +// Adjusted Binary LZW Compressor/Decompressor // +// Copyright (c) 2016 David Bryant // +// All Rights Reserved // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +//#define KERNEL_MODE +#ifdef KERNEL_MODE +#include +#include +#include +#include +#else +#include +#include +#include +#endif + + +/* This library implements the LZW general-purpose data compression algorithm. + * The algorithm was originally described as a hardware implementation by + * Terry Welsh here: + * + * Welch, T.A. “A Technique for High-Performance Data Compression.” + * IEEE Computer 17,6 (June 1984), pp. 8-19. + * + * Since then there have been enumerable refinements and variations on the + * basic technique, and this implementation is no different. The target of + * the present implementation is embedded systems, and so emphasis was placed + * on simplicity, fast execution, and minimal RAM usage. + * + * The symbols are stored in adjusted binary, which provides considerably + * better compression performance with virtually no speed penalty compared to + * the fixed sizes normally used. To ensure good performance on data with + * varying characteristics (like executable images) the encoder resets as + * soon as the dictionary is full. Also, worst-case performance is limited + * to about 8% inflation by catching poor performance and forcing an early + * reset before longer symbols are sent. + * + * The maximum symbol size is configurable on the encode side (from 9 bits + * to 12 bits) and determines the RAM footprint required by both sides and, + * to a large extent, the compression performance. This information is + * communicated to the decoder in the first stream byte so that it can + * allocate accordingly. The RAM requirements are as follows: + * + * maximum encoder RAM decoder RAM + * symbol size requirement requirement + * ----------------------------------------- + * 9-bit 1792 bytes 1024 bytes + * 10-bit 4352 bytes 3072 bytes + * 11-bit 9472 bytes 7168 bytes + * 12-bit 19712 bytes 15360 bytes + * + * This implementation uses malloc(), but obviously an embedded version could + * use static arrays instead if desired (assuming that the maxbits was + * controlled outside). + */ + +#define NULL_CODE -1 // indicates a NULL prefix +#define CLEAR_CODE 256 // code to flush dictionary and restart decoder +#define FIRST_STRING 257 // code of first dictionary string + +/* This macro writes the adjusted-binary symbol "code" given the maximum + * symbol "maxcode". A macro is used here just to avoid the duplication in + * the lzw_compress() function. The idea is that if "maxcode" is not one + * less than a power of two (which it rarely will be) then this code can + * often send fewer bits that would be required with a fixed-sized code. + * + * For example, the first code we send will have a "maxcode" of 257, so + * every "code" would normally consume 9 bits. But with adjusted binary we + * can actually represent any code from 0 to 253 with just 8 bits -- only + * the 4 codes from 254 to 257 take 9 bits. + */ + +#define WRITE_CODE(code,maxcode) do { \ + int code_bits = (maxcode) < 1024 ? \ + ((maxcode) < 512 ? 8 : 9) : \ + ((maxcode) < 2048 ? 10 : 11); \ + int extras = (1 << (code_bits + 1)) - (maxcode) - 1; \ + if ((code) < extras) { \ + shifter |= ((long)(code) << bits); \ + bits += code_bits; \ + } \ + else { \ + shifter |= ((long)(((code) + extras) >> 1) << bits); \ + bits += code_bits; \ + shifter |= ((long)(((code) + extras) & 1) << bits++); \ + } \ + do { (*dst)(shifter); shifter >>= 8; output_bytes++; \ + } while ((bits -= 8) >= 8); \ +} while (0) + +/* LZW compression function. Bytes (8-bit) are read and written through callbacks and the + * "maxbits" parameter specifies the maximum symbol size (9-12), which in turn determines + * the RAM requirement and, to a large extent, the level of compression achievable. A return + * value of EOF from the "src" callback terminates the compression process. A non-zero return + * value indicates one of the two possible errors -- bad "maxbits" param or failed malloc(). + */ + +int lzw_compress (void (*dst)(int), int (*src)(void), int maxbits) +{ + int next = FIRST_STRING, prefix = NULL_CODE, bits = 0, total_codes, c; + unsigned long input_bytes = 0, output_bytes = 0; + short *first_references, *next_references; + unsigned char *terminators; + unsigned long shifter = 0; + + if (maxbits < 9 || maxbits > 12) // check for valid "maxbits" setting + return 1; + + // based on the "maxbits" parameter, compute total codes and allocate dictionary storage + + total_codes = 1 << maxbits; +#ifdef KERNEL_MODE + first_references = ( short int * ) kmalloc (total_codes * sizeof (first_references [0])); + next_references = ( short int * ) kmalloc ((total_codes - 256) * sizeof (next_references [0])); + terminators = ( unsigned char * ) kmalloc ((total_codes - 256) * sizeof (terminators [0])); +#else + first_references = ( short int * ) malloc (total_codes * sizeof (first_references [0])); + next_references = ( short int * ) malloc ((total_codes - 256) * sizeof (next_references [0])); + terminators = ( unsigned char * ) malloc ((total_codes - 256) * sizeof (terminators [0])); +#endif + + if (!first_references || !next_references || !terminators) + return 1; // failed malloc() + + // clear the dictionary + + memset (first_references, 0, total_codes * sizeof (first_references [0])); + memset (next_references, 0, (total_codes - 256) * sizeof (next_references [0])); + memset (terminators, 0, (total_codes - 256) * sizeof (terminators [0])); + + (*dst)(maxbits - 9); // first byte in output stream indicates the maximum symbol bits + + // This is the main loop where we read input bytes and compress them. We always keep track of the + // "prefix", which represents a pending byte (if < 256) or string entry (if >= FIRST_STRING) that + // has not been sent to the decoder yet. The output symbols are kept in the "shifter" and "bits" + // variables and are sent to the output every time 8 bits are available (done in the macro). + + while ((c = (*src)()) != EOF) { + int cti; // coding table index + + input_bytes++; + + if (prefix == NULL_CODE) { // this only happens the very first byte when we don't yet have a prefix + prefix = c; + continue; + } + + if ((cti = first_references [prefix])) { // if any longer strings are built on the current prefix... + while (1) + if (terminators [cti - 256] == c) { // we found a matching string, so we just update the prefix + prefix = cti; // to that string and continue without sending anything + break; + } + else if (!next_references [cti - 256]) { // this string did not match the new character and + next_references [cti - 256] = next; // there aren't any more, so we'll add a new string + cti = 0; // and point to it with "next_reference" + break; + } + else + cti = next_references [cti - 256]; // there are more possible matches to check, so loop back + } + else // no longer strings are based on the current prefix, so now + first_references [prefix] = next; // the current prefix plus the new byte will be the next string + + // If "cti" is zero, we could not simply extend our "prefix" to a longer string because we did not find a + // dictionary match, so we send the symbol representing the current "prefix" and add the new string to the + // dictionary. Since the current byte "c" was not included in the prefix, that now becomes our new prefix. + + if (!cti) { + WRITE_CODE (prefix, next); // send symbol for current prefix (0 to next-1) + terminators [next - 256] = c; // newly created string has current byte as the terminator + prefix = c; // current byte also becomes new prefix for next string + + // This is where we bump the next string index and decide whether to clear the dictionary and start over. + // The triggers for that are either the dictionary is full or we've been outputting too many bytes and + // decide to cut our losses before the symbols get any larger. Note that for the dictionary full case we + // do NOT send the CLEAR_CODE because the decoder knows about this and we don't want to be redundant. + + if (++next == total_codes || output_bytes > 8 + input_bytes + (input_bytes >> 4)) { + if (next < total_codes) + WRITE_CODE (CLEAR_CODE, next); + + // clear the dictionary and reset the byte counters -- basically everything starts over + // except that we keep the last pending "prefix" (which, of course, was never sent) + + memset (first_references, 0, total_codes * sizeof (first_references [0])); + memset (next_references, 0, (total_codes - 256) * sizeof (next_references [0])); + memset (terminators, 0, (total_codes - 256) * sizeof (terminators [0])); + input_bytes = output_bytes = 0; + next = FIRST_STRING; + } + } + } + + // we're done with input, so if we've received anything we still need to send that pesky pending prefix... + + if (prefix != NULL_CODE) { + WRITE_CODE (prefix, next); + + if (++next == total_codes) // watch for clearing to the first string to stay in step with the decoder! + next = FIRST_STRING; // (this was actually a corner-case bug that did not trigger often) + } + + WRITE_CODE (next, next); // the maximum possible code is always reserved for our END_CODE + + if (bits) // finally, flush any pending bits from the shifter + (*dst)(shifter); + +#ifdef KERNEL_MODE + kfree (terminators); kfree (next_references); kfree (first_references); +#else + free (terminators); free (next_references); free (first_references); +#endif + return 0; +} + +/* LZW decompression function. Bytes (8-bit) are read and written through callbacks. The + * "maxbits" parameter is read as the first byte in the stream and controls how much memory + * is allocated for decoding. A return value of EOF from the "src" callback terminates the + * compression process (although this should not normally occur). A non-zero return value + * indicates an error, which in this case can be a bad "maxbits" read from the stream, a + * failed malloc(), or if an EOF is read from the input stream before the compression + * terminates naturally with END_CODE. + */ + +int lzw_decompress (void (*dst)(int), int (*src)(void)) +{ + int read_byte, next = FIRST_STRING, prefix = CLEAR_CODE, bits = 0, total_codes; + unsigned char *terminators, *reverse_buffer; + unsigned long shifter = 0; + short *prefixes; + + if ((read_byte = ((*src)())) == EOF || (read_byte & 0xfc)) //sanitize first byte + return 1; + + // based on the "maxbits" parameter, compute total codes and allocate dictionary storage + + total_codes = 512 << (read_byte & 0x3); +#ifdef KERNEL_MODE + reverse_buffer = ( unsigned char *) kmalloc ((total_codes - 256) * sizeof (reverse_buffer [0])); + prefixes = ( short * ) kmalloc ((total_codes - 256) * sizeof (prefixes [0])); + terminators = ( unsigned char * ) kmalloc ((total_codes - 256) * sizeof (terminators [0])); +#else + reverse_buffer = ( unsigned char *) malloc ((total_codes - 256) * sizeof (reverse_buffer [0])); + prefixes = ( short * ) malloc ((total_codes - 256) * sizeof (prefixes [0])); + terminators = ( unsigned char * ) malloc ((total_codes - 256) * sizeof (terminators [0])); +#endif + + if (!reverse_buffer || !prefixes || !terminators) // check for mallco() failure + return 1; + + // This is the main loop where we read input symbols. The values range from 0 to the code value + // of the "next" string in the dictionary (although the actual "next" code cannot be used yet, + // and so we reserve that code for the END_CODE). Note that receiving an EOF from the input + // stream is actually an error because we should have gotten the END_CODE first. + + while (1) { + int code_bits = next < 1024 ? (next < 512 ? 8 : 9) : (next < 2048 ? 10 : 11), code; + int extras = (1 << (code_bits + 1)) - next - 1; + + do { + if ((read_byte = ((*src)())) == EOF) { +#ifdef KERNEL_MODE + kfree (terminators); kfree (prefixes); kfree (reverse_buffer); +#else + free (terminators); free (prefixes); free (reverse_buffer); +#endif + return 1; + } + + shifter |= (long) read_byte << bits; + } while ((bits += 8) < code_bits); + + // first we assume the code will fit in the minimum number of required bits + + code = (int) shifter & ((1 << code_bits) - 1); + shifter >>= code_bits; + bits -= code_bits; + + // but if code >= extras, then we need to read another bit to calculate the real code + // (this is the "adjusted binary" part) + + if (code >= extras) { + if (!bits) { + if ((read_byte = ((*src)())) == EOF) { +#ifdef KERNEL_MODE + kfree (terminators); kfree (prefixes); kfree (reverse_buffer); +#else + free (terminators); free (prefixes); free (reverse_buffer); +#endif + return 1; + } + + shifter = (long) read_byte; + bits = 8; + } + + code = (code << 1) - extras + (shifter & 1); + shifter >>= 1; + bits--; + } + + if (code == next) // sending the maximum code is reserved for the end of the file + break; + else if (code == CLEAR_CODE) // otherwise check for a CLEAR_CODE to start over early + next = FIRST_STRING; + else if (prefix == CLEAR_CODE) { // this only happens at the first symbol which is always sent + (*dst)(code); // literally and becomes our initial prefix + next++; + } + // Otherwise we have a valid prefix so we step through the string from end to beginning storing the + // bytes in the "reverse_buffer", and then we send them out in the proper order. One corner-case + // we have to handle here is that the string might be the same one that is actually being defined + // now (code == next-1). Also, the first 256 entries of "terminators" and "prefixes" are fixed and + // not allocated, so that messes things up a bit. + else { + int cti = (code == next-1) ? prefix : code; + unsigned char *rbp = reverse_buffer, c; + + do *rbp++ = cti < 256 ? cti : terminators [cti - 256]; // step backward through string... + while ((cti = (cti < 256) ? NULL_CODE : prefixes [cti - 256]) != NULL_CODE); + + c = *--rbp; // the first byte in this string is the terminator for the last string, which is + // the one that we'll create a new dictionary entry for this time + + do (*dst)(*rbp); // send string in corrected order (except for the terminator + while (rbp-- != reverse_buffer); // which we don't know yet) + + if (code == next-1) + (*dst)(c); + + prefixes [next - 1 - 256] = prefix; // now update the next dictionary entry with the new string + terminators [next - 1 - 256] = c; // (but we're always one behind, so it's not the string just sent) + + if (++next == total_codes) // check for full dictionary, which forces a reset (and, BTW, + next = FIRST_STRING; // means we'll never use the dictionary entry we just wrote) + } + + prefix = code; // the code we just received becomes the prefix for the next dictionary string entry + // (which we'll create once we find out the terminator) + } + +#ifdef KERNEL_MODE + kfree (terminators); kfree (prefixes); kfree (reverse_buffer); +#else + free (terminators); free (prefixes); free (reverse_buffer); +#endif + return 0; +} diff --git a/device/gxx-linux/motorboard/motorboard.cpp b/device/gxx-linux/motorboard/motorboard.cpp index 1c6cb0f..48d3258 100644 --- a/device/gxx-linux/motorboard/motorboard.cpp +++ b/device/gxx-linux/motorboard/motorboard.cpp @@ -7,31 +7,48 @@ #include "config.h" #include "StopWatch.h" #include "applog.h" -#include "Capturer.h" +#include "StateControl.h" +#include "Displaydef.h" +#include "MotorConfig.h" +#include "DisplayCenter.h" + static const std::string loggername = "MotorBoard"; -MotorBoard::MotorBoard() +MotorBoard::MotorBoard(std::shared_ptr wake) : devPort(MOTOR_UART), - m_glue({nullptr, nullptr, nullptr,nullptr,nullptr,nullptr}) + m_glue({nullptr, nullptr, nullptr,nullptr,nullptr,nullptr,nullptr}) { LOG_INIT(); - m_uartEnable.reset(new GpioOut(152)); - m_uartEnable->setDirection(Gpio::out); - // m_uartEnable->setEdge(Gpio::rising); + //m_uartEnable.reset(new GpioOut(149)); //m_uartEnable->setValue(Gpio::Low); std::this_thread::sleep_for(std::chrono::milliseconds(10)); m_regsAccess.reset(new UartRegsAccess(devPort, bauds, 0x07, 0x87)); m_intPinMonitor.reset(new PinMonitor(intport, std::bind(&MotorBoard::pin_call, this, std::placeholders::_1))); - //m_scansensorMonitor.reset(new PinMonitor(149, std::bind(&MotorBoard::scansensor_call, this, std::placeholders::_1))); //m_uartEnable->setValue(Gpio::High); std::this_thread::sleep_for(std::chrono::milliseconds(10)); m_os_mode = os_mode(); + m_statecontrol.reset(new StateControl(m_regsAccess,wake)); + m_wake = wake; } + static int paperinnum = 0; -void MotorBoard::start() +void MotorBoard::start(HGScanConfig cfg) { + m_config = cfg; keep_last_paper=false; + paperinnum = 0; + m_paperout_count = 0; + clear_error(); + set_time_error(120); + set_double_inpect(m_config.g200params.double_feed_enbale); + set_staple_inpect(m_config.g200params.stable_enbale); + set_paper_inspect(0); + set_auto_paper(m_config.g200params.is_autopaper,m_config.g200params.en_anlogic_key); + set_screw_inpect(m_config.g200params.screw_detect_enable); + set_screw_level(m_config.g200params.screw_detect_level); + set_long_paper(true); + unsigned int val; SMBCONFIG *smbc = (SMBCONFIG *)(&val); read(0, val); @@ -39,18 +56,29 @@ void MotorBoard::start() write(0, val); smbc->enable = 1; write(0, val); - paperinnum =0 ; + + en_lifter(); } void MotorBoard::stop() { + printf("MotorBoard Stop \n"); unsigned int val; SMBCONFIG *smbc = (SMBCONFIG *)(&val); read(0, val); smbc->enable = 0; write(0, val); } - +bool MotorBoard::en_lifter() +{ + unsigned int val; + SMBCONFIG *smbc = (SMBCONFIG *)(&val); + read(0x00, val); + smbc->lifter_en = 1; + write(0x00, val); + smbc->lifter_en = 0; + return write(0x00, val); +} void MotorBoard::pick_paper(void) { @@ -59,74 +87,14 @@ void MotorBoard::pick_paper(void) read(0x00, val); smbc->pick_paper = 0; write(0x00, val); + std::this_thread::sleep_for(std::chrono::microseconds(500)); smbc->pick_paper = 1; write(0x00, val); // smbc->pick_paper = 0; // write(0x00, val); } -void MotorBoard::clear_error() -{ - unsigned int val; - SMBCONFIG *smbc = (SMBCONFIG *)(&val); - read(0, val); - smbc->error_clean = 1; - write(0, val); - smbc->error_clean = 0; - write(0, val); -} - -bool MotorBoard::wait_paper_in(int timeout_ms) -{ - return cv_paper_in.wait(timeout_ms); -} - -bool MotorBoard::wait_paper_out(int timeout_ms) -{ - return cv_paper_out.wait(timeout_ms); -} - - -int MotorBoard::os_mode() -{ - unsigned int val; - read(0x02, val); - SMB_MODE *smb_mode = (SMB_MODE *)&val; - return smb_mode->scan_mode; -} - -bool MotorBoard::paper_ready() -{ - unsigned int val; - read(0x02, val); - SMB_MODE *smb_mode = (SMB_MODE *)&val; - return smb_mode->feeding_paper_ready; -} -bool MotorBoard::is_converopen() -{ - unsigned int val; - read(0x02, val); - SMBSTATUS *smb_mode = (SMBSTATUS *)&val; - return smb_mode->open_machine; -} -bool MotorBoard::is_scanning() -{ - unsigned int val; - read(0x02, val); - SMB_MODE *smb_mode = (SMB_MODE *)&val; - return smb_mode->work_status; -} - -bool MotorBoard::is_jam() -{ - return false; -} - -void MotorBoard::motor_reset(){ -} - -void MotorBoard::clean_paper_road() -{ +void MotorBoard::clean_paper_road(){ unsigned int val; SMB_FUNC *smbc = (SMB_FUNC *)(&val); read(6, val); @@ -140,6 +108,83 @@ void MotorBoard::clean_paper_road() else{ printf("\n 非空闲模式不允许清理纸道!!!!"); } + +} + +void MotorBoard::clear_error() +{ + unsigned int val; + SMBCONFIG *smbc = (SMBCONFIG *)(&val); + read(0, val); + smbc->error_clean = 1; + write(0, val); + smbc->error_clean = 0; + write(0, val); +} + +bool MotorBoard::wait_arrival_top(int timeout_ms) +{ + return cv_arrival_top.wait(timeout_ms); +} + +bool MotorBoard::wait_paper_in(int timeout_ms) +{ + return cv_paper_in.wait(timeout_ms); +} + +bool MotorBoard::wait_error(int timeout_ms) +{ + return cv_error.wait(timeout_ms); +} + +bool MotorBoard::wait_paper_out(int timeout_ms) +{ + // StopWatch sw; + // LOG_TRACE("wait_paper_out "); + // while(sw.elapsed_ms() 0) + // { + // m_paperout_count--; + // return true; + // } + // std::this_thread::sleep_for(std::chrono::milliseconds(1)); + // } + // return false; + return cv_paper_out.wait(timeout_ms); +} + +bool MotorBoard::wait_done(int timeout_ms) +{ + return cv_scan_done.wait(timeout_ms); +} + +int MotorBoard::os_mode() +{ + // unsigned int val; + // read(0x02, val); + // SMB_MODE *smb_mode = (SMB_MODE *)&val; + // return smb_mode->scan_mode; + unsigned int val; + read(0x06,val); + SMB_FUNC smb_func = *(SMB_FUNC*)&val; + return smb_func.param.work_mode == 1; +} + +bool MotorBoard::paper_ready() +{ + unsigned int val; + read(0x02, val); + SMB_MODE *smb_mode = (SMB_MODE *)&val; + return smb_mode->feeding_paper_ready; +} + +bool MotorBoard::is_scanning() +{ + unsigned int val; + read(0x02, val); + SMB_MODE *smb_mode = (SMB_MODE *)&val; + return smb_mode->work_status; } int MotorBoard::paper_counter() @@ -150,31 +195,54 @@ int MotorBoard::paper_counter() return smb_mode->scan_num; } +bool MotorBoard::set_paper_inspect_param(unsigned int value /* = 1000 */) +{ + unsigned int val; + if (!read(0x04, val)) + return false; + SMBCONFIGEXT *smb_config_ext = (SMBCONFIGEXT *)&val; + smb_config_ext->error_range_set = value; + return write(0x04, val); +} bool MotorBoard::get_keeplastpaper(){ return keep_last_paper; } +bool MotorBoard::set_paper_inpect_info(unsigned int value) +{ + unsigned int val; + if (!read(0x04, val)) + return false; + SMBCONFIGEXT *smb_config_ext = (SMBCONFIGEXT *)&val; + smb_config_ext->paper_infor = value; + return write(0x04, val); +} + +bool MotorBoard::set_paper_inspect(bool enable /* = true */) +{ + unsigned int val; + if (!read(0x04, val)) + return false; + SMBCONFIGEXT *smb_config_ext = (SMBCONFIGEXT *)&val; + smb_config_ext->paper_size_check_en = enable; + return write(0x04, val); +} bool MotorBoard::set_double_inpect(bool enable) { unsigned int val; if (!read(0x00, val)) return false; + enable?m_statecontrol->lcdcontrol(4):m_statecontrol->lcdcontrol(5); SMBCONFIG *smb_config = (SMBCONFIG *)&val; smb_config->double_paper = enable; return write(0x00, val); } - -bool MotorBoard::set_auto_paper(bool enable){ - unsigned int val; - if (!read(0x00, val)) - return false; - SMBCONFIG *smb_config = (SMBCONFIG *)&val; - smb_config->autofeed_mode = enable; - return write(0x00, val); +bool MotorBoard::get_doublle_inpect() +{ + return 0; } - bool MotorBoard::set_staple_inpect(bool enable) { unsigned int val; @@ -184,8 +252,30 @@ bool MotorBoard::set_staple_inpect(bool enable) smb_config->staple_enable = enable; return write(0x00, val); } +bool MotorBoard::get_staple_inpect() +{ + return 0; +} +bool MotorBoard::set_cuospeed(int value) +{ + unsigned int val; + if (!read(0x4, val)) + return false; + SMBCONFIGEXT *smb_config = (SMBCONFIGEXT *)&val; + smb_config->cuo_speed = value; + return write(0x04, val); +} +bool MotorBoard::set_en600DPI(bool en) +{ + unsigned int val; + if (!read(0x00, val)) + return false; + SMBCONFIG *smb_config = (SMBCONFIG *)&val; + smb_config->dpi600 = en?1:0; + return write(0x00, val); +} bool MotorBoard::set_color_mode(int mode) { unsigned int val; @@ -195,8 +285,12 @@ bool MotorBoard::set_color_mode(int mode) smb_config->color_mode = mode; return write(0x00, val); } +int MotorBoard::get_color_mode() +{ + return 0; +} -bool MotorBoard::set_speed_mode(int mode,int dpi,int iscolor) +bool MotorBoard::set_speed_mode(int mode) { unsigned int val; if (!read(0x00, val)) @@ -219,47 +313,34 @@ int MotorBoard::get_speed_mode() return smb_config->v_setting; } -bool MotorBoard::set_cuospeed(unsigned int speed,uint dpi,uint iscolor) -{ - unsigned int val; - if (!read(0x04, val)) - return -1; - SMB_CONFIG_EXT *smb_config = (SMB_CONFIG_EXT *)&val; - smb_config->cuo_speed = speed; - return write(0x04,val); - -} - std::shared_ptr MotorBoard::regs() { return m_regsAccess; } - -static int pinindex=0; +static int countindex =0; void MotorBoard::pin_call(unsigned int pinNum) { static int index = 0; - LOG_TRACE(string_format("pin %d", index++)); - int os_m = os_mode(); - if (m_os_mode != os_m) - { - m_os_mode = os_m; - if (m_glue.m_os_mode_call) - m_glue.m_os_mode_call(m_os_mode); - } + // int os_m = os_mode(); //安路屏蔽计数 扫描过程中无法操作按键 + // if (m_os_mode != os_m) + // { + // m_os_mode = os_m; + // cv_os_mode.notify_all(); + // if (m_glue.m_os_mode_call) + // m_glue.m_os_mode_call(m_os_mode); + // } - if (m_os_mode) - { - LOG_TRACE("not scan mode"); - return; - } + // if (m_os_mode) //安路屏蔽计数返回 以刷新计数状态 + // { + // LOG_TRACE("not scan mode"); + // return; + // } unsigned int val; SMBSTATUS *smb_status = (SMBSTATUS *)&val; if (!read(0x01, val)) LOG_TRACE("read error"); LOG_TRACE(string_format("status %08x", val)); - //printf("\n reg 1 val =%d",val); if(val & 0x800){ //printf("\n keep_last_paper "); keep_last_paper=true; @@ -279,11 +360,38 @@ void MotorBoard::pin_call(unsigned int pinNum) if(m_glue.m_auto_paper) m_glue.m_auto_paper(1); } - if (val & 0xAFE) + if (val & 0x7c003FE) { + SetKeyState(false); + cv_error.notify_all(); if (m_glue.m_error_call) m_glue.m_error_call(val & 0x30efe); //0xefe index of 16:aquireimage error index of bit 17 :size check error - + if(val & 0x30efe){ + cv_paper_out.notify_all(); + m_paperout_count++; + } + errormsg(val & 0x1c003fa); + if((val & 0x4) ||(val & 0x02000000)) + { + if(m_glue.m_coveropen_call) + m_glue.m_coveropen_call((val & 0x4));//cover open & 0x04 + if(val & 0x4){ + PutMsg(DisType::Dis_Err_CoverOpen,0,ClearScreen::All); + set_auto_paper(false,false); + autopaperkeystop?autopaperkeystop():void(0); + if(m_statecontrol){ + m_statecontrol->setcoverstate(true); + m_statecontrol->setmenuindex(0); + } + } + else{ + PutMsg(DisType::Dis_Idel,0,ClearScreen::All); + m_statecontrol?m_statecontrol->setcoverstate(false):void(); + } + return; + } + if(smb_status->double_clean_f) + PutMsg(DisType::Dis_Idel,0,ClearScreen::All); LOG_TRACE("error"); return; } @@ -292,48 +400,56 @@ void MotorBoard::pin_call(unsigned int pinNum) if (!smb_status->scan_pulse) { cv_paper_in.notify_all(); - LOG_TRACE("paper in"); - printf("\n paper pulse num = %d ", paperinnum++); + unsigned int papercount = 0; + read(0x02,papercount); + SMBMODE smbmode = *(SMBMODE*)&papercount; + printf("paper in arm count = %d ,motorcount = %d time = %s\n",++countindex,smbmode.scan_num); + startcapimage(true); + PutMsg(DisType::Dis_Scan_Page, smbmode.scan_num,ClearScreen::BOT); } - if(smb_status->paper_left) { cv_paper_out.notify_all(); - LOG_TRACE("paper left"); + m_paperout_count++; + //printf("paper out time = %s \n",GetCurrentTimeStamp(2).c_str()); + startcapimage(true); + LOG_TRACE(string_format("m_paperout_count %s",to_string(m_paperout_count))); } } if (val & 0x400) { LOG_TRACE("done"); + cv_scan_done.notify_all(); if (m_glue.m_scan_done_call) m_glue.m_scan_done_call(); + cv_paper_out.notify_all(); + clear_error(); + SetKeyState(false); + if(m_wake.get()) + m_wake->setsleepfalg(false); } } -void MotorBoard::set_capture(std::shared_ptr cap) -{ - m_cap= cap; -} - -void MotorBoard::scansensor_call(unsigned int pinNum) -{ - // static int indexscansensor=0; - // m_uartEnable->setValue(Gpio::High); - // LOG_TRACE(string_format(" gpio149 call times -%d ", indexscansensor++)); - // cv_paper_in.notify_all(); - // m_uartEnable->setValue(Gpio::Low); -} bool MotorBoard::write(unsigned int addr, unsigned int val) { - return m_regsAccess->write(addr, val); + return m_regsAccess.get()?m_regsAccess->write(addr, val):false; } bool MotorBoard::read(unsigned int addr, unsigned int &val) { - return m_regsAccess->read(addr, val); + return m_regsAccess.get()?m_regsAccess->read(addr, val):false; } + bool MotorBoard::set_time_error(int value){ + unsigned int val; + if (!read(0x05, val)) + return false; + SMBCONFIGTIME *smb_config = (SMBCONFIGTIME *)&val; + smb_config->error_time_set = value; + return write(0x05, val); + } + void MotorBoard::set_callbacks(MotorBoardGlue glue) { m_glue = glue; @@ -366,6 +482,16 @@ bool MotorBoard::set_screw_level(int level) return write(0x00, val); } +bool MotorBoard::set_auto_paper(bool enable,bool enkey){ + unsigned int val; + if (!read(0x00, val)) + return false; + m_statecontrol?m_statecontrol->setautopaperflag(enable,enkey):void(0); + SMBCONFIG *smb_config = (SMBCONFIG *)&val; + smb_config->autofeed_mode = enable; + return write(0x00, val); +} + bool MotorBoard::set_long_paper(bool enable) { unsigned int val; @@ -385,3 +511,180 @@ int MotorBoard::get_screw_level() SMBCONFIG *smb_mode = (SMBCONFIG *)&val; return smb_mode->skew_parameter; } + +void MotorBoard::start_countmode() +{ + unsigned int regval=0; + + read(0x06,regval); + LOG_TRACE(string_format("func6 regval = %08x",regval)); + SMBFUNC func = *(SMBFUNC*)®val; + func.param.work_mode =1; + func.param.func_feed_mid = 1; + func.param.func_clear_count = 1; + LOG_TRACE(string_format("func6 value = %08x",func.value)); + write(0x06,func.value); + func.param.func_encount = 1; + func.param.key_sound = 1; + func.param.func_clear_count = 0; + LOG_TRACE(string_format("func6 value = %08x",func.value)); + write(0x06,func.value); + func.param.func_encount = 0; + func.param.key_sound = 0; + LOG_TRACE(string_format("func6 value = %08x",func.value)); + write(0x06,func.value); +} + + +void MotorBoard::PutMsg(DisType type,int value,ClearScreen clearscreen) +{ + if(m_statecontrol.get()) + m_statecontrol->PutMsg(type,value,clearscreen); +} + +void MotorBoard::errormsg(uint value) +{ + if (value & 0x2) + PutMsg(DisType::Dis_Err_NoPaper,0,ClearScreen::All); + else if (value & 0x8) + PutMsg(DisType::Dis_Err_FeedError,0,ClearScreen::All); + // else if (value & 0x10) + // PutMsg(DisType::Dis_Err_JamIn,0,ClearScreen::All); + else if (value & 0x20) + PutMsg(DisType::Dis_Err_DoubleFeed,0,ClearScreen::All); + else if (value & 0x40) + PutMsg(DisType::Dis_Err_Stable,0,ClearScreen::All); + else if (value & 0x80) + PutMsg(DisType::Dis_Err_PaperScrew,0,ClearScreen::All); + else if (value & 0x00010000) + PutMsg(DisType::Dis_Err_AqrImgTimeout,0,ClearScreen::All); + else if((value & 0x1000010) == 0x1000010) + PutMsg(DisType::Dis_Err_JamIn,3,ClearScreen::All); + else if((value & 0x800010) == 0x800010) + PutMsg(DisType::Dis_Err_JamIn,2,ClearScreen::All); + else if((value & 0x400010) == 0x400010) + PutMsg(DisType::Dis_Err_JamIn,1,ClearScreen::All); +} + +void MotorBoard::SetKeyState(bool value) +{ + if(m_statecontrol) + m_statecontrol->setrunstate(value); +} + + +void MotorBoard::set_keystopenable(bool value){ + unsigned int regval=0; + read(0x06,regval); + LOG_TRACE(string_format("func6 regval = %08x",regval)); + SMBFUNC func = *(SMBFUNC*)®val; + func.param.key_stop_enable = value; + write(0x06,regval); +} + + +void MotorBoard::set_freq(int motor_choose,int speedmode,int colormode,int dpi) +{ + MotorConfig cf; + auto params = cf.GetMotorSpeedParams(motor_choose == 1?0:1,MotorConfig::MTBDType::MT_DRV); + MotorSpeedParam param; + //printf("\n---node.dpi ==%d && node.colormode == %d && node.speed == %d----- ",dpi,colormode,speedmode); + for(auto &node : params) + { + if(node.dpi == dpi && node.colormode == colormode && node.speed == speedmode) + { + param = node.mt_param; + //printf("\n-------------------------------------------------"); + break; + } + } + std::vector table; + if(motor_choose == 0) + { + int x = (dpi == 1?(jsonconfig().getscannerinfo().chu_motor_speed_200):(dpi == 2?jsonconfig().getscannerinfo().chu_motor_speed_300 : jsonconfig().getscannerinfo().chu_motor_speed_600)); + unsigned int regval=0; + read(0x06,regval); + SMBFUNC func = *(SMBFUNC*)®val; + func.param.motor_choose = motor_choose; + func.param.wr_en = 1; + write(0x06,func.value); + write(0x04,x); + //func.param.wr_en = 0; + //write(0x06,func.value); + return ; + } + if(motor_choose == 1) + table = frep_cfg(param.finalPeriod,param.Fmin,param.stepnum,param.a,param.offset,param.finalDelay,param.acceleration_time); + if(motor_choose == 2) + table = frep_cfg(param.finalPeriod,param.Fmin,param.stepnum,param.a,param.offset,param.finalDelay,param.acceleration_time); + if(motor_choose == 3) + table = frep_cfg(param.finalPeriod,param.Fmin,param.stepnum,param.a,param.offset,param.finalDelay,param.acceleration_time); + unsigned int regval=0; + read(0x06,regval); + SMBFUNC func = *(SMBFUNC*)®val; + int start_addr_cuo = 0; +#ifdef G200 + if(motor_choose ==1 && speedmode > 1 && dpi <3) + start_addr_cuo = 63; + if(motor_choose ==1 && dpi ==3) + start_addr_cuo = 127; +#endif + printf("\nstart_addr_cuo =%d ",start_addr_cuo); + for(int i =0;i<256;i++) + { + func.param.motor_choose = motor_choose; + func.param.wr_en = 1; + func.param.motor_addr =i; + write(0x06,func.value); + write(0x04,isetautopaperstopcallback([&]{ + autopaperkeystop?autopaperkeystop():void(0); + if(m_config.g200params.is_autopaper) + set_auto_paper(false,false); + }); + PutMsg(DisType::Dis_Idel,0,ClearScreen::All); +} + +void MotorBoard::release_statecontrol() +{ + autopaperkeystop?autopaperkeystop():void(0); + set_auto_paper(false,false); + m_statecontrol.reset(); + m_regsAccess.reset(); + m_intPinMonitor.reset(); + +} + +void MotorBoard::setautopaperkeystopcallback(std::function func){ + if(func) + autopaperkeystop = func; + m_statecontrol?m_statecontrol->setautopaperstopcallback([&]{ + autopaperkeystop?autopaperkeystop():void(0); + set_auto_paper(false,false); + }):void(0); +} +void MotorBoard::startcapimage(bool value) +{ + // if(m_config.g200params.is_fixedpaper) + // return; + // FILE *fp = fopen("/sys/class/tty/ttyUSB0/device/huagao_scanner", "w"); + // if (fp == NULL) + // perror("startcapimage open filed"); + // else{ + // fprintf(fp, "%d", value ? 1 : 0); + // fclose(fp); + // } +} \ No newline at end of file diff --git a/device/gxx-linux/motorboard/motorboard.h b/device/gxx-linux/motorboard/motorboard.h index 87d0def..ceda2eb 100644 --- a/device/gxx-linux/motorboard/motorboard.h +++ b/device/gxx-linux/motorboard/motorboard.h @@ -1,6 +1,40 @@ #pragma once -#include "Imotorboard.h" +#include +#include +#include +#include +#include "autoevent.hpp" +#include "commondef.h" +#include +#include +#include "wakeup.hpp" +//static std::vector frep_cfg(int a,int b,float k,int s) +static std::vector frep_cfg(int finalPeriod, int Fmin, float stepnum, float a, float offset, float finalDelay,float acceleration_time) +{ + std::vector freq; + int freq_word = 0; + int pulse_word = 0; + for(int i =1;i<=256;i++) + { + freq_word = 8000000/((Fmin+(finalPeriod-Fmin)/(1+exp((-1)*(offset+a*(double)(i)*stepnum))))*2); + pulse_word = ((8000000/acceleration_time)/63)/freq_word; + //printf("\nfreq_word = %d pulse_word = %d",freq_word,pulse_word); + freq.push_back((pulse_word&0xffff)+((freq_word&0xffff)<<16)); + } + return freq; +} +class IRegsAccess; +class PinMonitor; +class Gpio; +class StateControl; +enum class DisType; +enum class ClearScreen; +/* +注: + 安路电机板已去除幅面检测以及休眠配置相关寄存器操作, + 休眠将由Arm 进行控制 +*/ typedef struct SMB_CONFIG { @@ -33,22 +67,27 @@ typedef struct SMB_STATUS unsigned int m1_paper_sin : 1; unsigned int open_machine : 1; unsigned int pick_failed : 1; - unsigned int stop_jam : 1; // 5 + unsigned int stop_jam : 1;//5 unsigned int double_paper : 1; unsigned int staple : 1; unsigned int papertilted : 1; unsigned int count_pulse : 1; - unsigned int scan_mode_change : 1; // 5 + unsigned int scan_mode_change : 1;//5 unsigned int motor_status : 1; unsigned int keep_last_paper : 1; unsigned int sleep_set : 1; - unsigned int sleep_conf : 3; + unsigned int sleep_conf : 3;//6 unsigned int dsp_get_paper_error : 1; unsigned int paper_check_result : 1; - unsigned int arrival_top:1;//������ֽ - unsigned int arrival_top_int:1;//���ﶥ���ж� + unsigned int arrival_top:1;//顶部无纸 + unsigned int arrival_top_int:1;//到达顶部中断 unsigned int auto_feed:1;//4 - unsigned int paper_left:1; + unsigned int paper_left:1; + unsigned int jam_1 : 1; //进纸口 + unsigned int jam_2 : 1; //纸道 + unsigned int jam_3 : 1; //出纸口 + unsigned int cover_closed : 1; //已关盖 + unsigned int double_clean_f : 1; //液晶双张错误清除 } SMBSTATUS; typedef struct SMB_MODE @@ -95,49 +134,64 @@ typedef union SMB_FUNC unsigned int value; } SMBFUNC; -class MotorBoard : public IMotorBoard +class MotorBoard { public: - MotorBoard(); - - void start() override; - void stop() override; - void clear_error() override; - void pick_paper() override; - void stop_pick_paper() override{}; - int os_mode() override; - bool paper_ready() override; - bool is_scanning() override; - bool is_jam() override; - int paper_counter() override; - bool is_converopen() override; - bool set_long_paper(bool enable) override; - bool set_double_inpect(bool enable) override; - bool set_staple_inpect(bool enable) override; - bool set_auto_paper(bool enable) override; - bool set_color_mode(int mode) override; - int get_speed_mode() override; - bool set_speed_mode(int mode,int dpi,int iscolor) override; - bool set_screw_inpect(bool enable) override; - bool get_screw_inpect() override; - bool set_screw_level(int level) override; - int get_screw_level() override; - bool wait_paper_out(int timeout_ms) override; - bool wait_paper_in(int timeout_ms) override; - bool read(unsigned int addr, unsigned int &val) override; - bool write(unsigned int addr, unsigned int val) override; - bool set_cuospeed(unsigned int speed,uint dpi = 0,uint iscolor = 1) override; - void set_callbacks(MotorBoardGlue glue) override; - bool get_keeplastpaper() override; - std::shared_ptr regs() override; - void set_capture(std::shared_ptr cap) override; - void motor_reset() override; - void LedControlOption(HG_LedOption option,uint32_t time) override{}; - void clean_paper_road() override; + MotorBoard(std::shared_ptr wake); + void start(HGScanConfig cfg); + void stop(); + void clear_error(); + void pick_paper(); + int os_mode(); + bool paper_ready(); + bool is_scanning(); + int paper_counter(); + bool en_lifter(); + bool set_long_paper(bool enable); + bool set_double_inpect(bool enable); + bool get_doublle_inpect(); + bool set_staple_inpect(bool enable); + bool get_staple_inpect(); + bool set_color_mode(int mode); + int get_color_mode(); + int get_speed_mode(); + bool set_auto_paper(bool enable,bool enkey); + bool set_speed_mode(int mode); + bool set_screw_inpect(bool enable); + bool get_screw_inpect(); + bool set_screw_level(int level); + int get_screw_level(); + bool wait_arrival_top(int timeout_ms); + bool wait_paper_in(int timeout_ms); + bool wait_paper_out(int timeout_ms); + bool wait_error(int timeout_ms); + bool wait_done(int timeout_ms); + bool read(unsigned int addr, unsigned int &val); + bool write(unsigned int addr, unsigned int val); + bool set_paper_inspect_param(unsigned int value = 1000); + bool set_paper_inpect_info(unsigned int value); + bool set_paper_inspect(bool enable = true); + void set_callbacks(MotorBoardGlue glue); + bool set_cuospeed(int value); + bool get_keeplastpaper(); + bool set_en600DPI(bool en); + bool set_time_error(int value); + void start_countmode(); + std::shared_ptr regs(); + void PutMsg(DisType type,int value,ClearScreen clearscreen); + void SetKeyState(bool value); + void set_freq(int motor_choose,int speedmode,int colormode,int dpi); + void set_keystopenable(bool value); + void init_statecontrol(); + void release_statecontrol(); + void setautopaperkeystopcallback(std::function func); + void errormsg(uint value); + void startcapimage(bool value); + void clean_paper_road(); private: void pin_call(unsigned int pinNum); - void scansensor_call(unsigned int pinNum); + const std::string devPort; const unsigned int bauds = 921600; const int readflag = 0x07; @@ -145,12 +199,18 @@ private: const unsigned int intport = 151; std::shared_ptr m_regsAccess; std::shared_ptr m_intPinMonitor; - std::shared_ptr m_uartEnable; - AutoSemaphore cv_paper_out; + std::shared_ptr m_statecontrol; + std::shared_ptr m_wake; + std::atomic_uint m_paperout_count; AutoSemaphore cv_paper_in; + AutoSemaphore cv_arrival_top; + AutoSemaphore cv_paper_out; + AutoSemaphore cv_error; + AutoSemaphore cv_scan_done; + AutoSemaphore cv_os_mode; + HGScanConfig m_config; unsigned int m_os_mode; volatile bool keep_last_paper; MotorBoardGlue m_glue; - std::shared_ptr m_cap; - bool b_paperin; + std::function autopaperkeystop; }; \ No newline at end of file diff --git a/device/gxx-linux/motorboard/motormanager.cpp b/device/gxx-linux/motorboard/motormanager.cpp deleted file mode 100644 index d46d4f7..0000000 --- a/device/gxx-linux/motorboard/motormanager.cpp +++ /dev/null @@ -1,320 +0,0 @@ -#include "motormanager.h" -#include "MotorControl.h" -#include "sensormonitor.h" -#include -#include "Led.h" - -MotorManager::MotorManager():m_motorcontrol(new MotorControl()), - m_ledcontrol(new LedControl()), - is_usb_connect(false), - is_sleeping(false), - is_autopaper(false), - is_motor_run(false), - autopaper_state_change(false), - autopaperthread(1), - m_glue({nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}) -{ - GetorSetSysClassValue(false,HG_PWM_FAN,false); - GetorSetSysClassValue(false,HG_MOTOR_FAN,false); - m_sensormonitor.reset(new SensorMonitor([&](int value){pincall(value);})); - m_ledcontrol->option(HG_WHITE_ON,300); -} - -MotorManager::~MotorManager() -{ - -} -bool MotorManager::GetOrSetUsbConnectFlag(bool isGet,bool value){ - if(isGet) - return is_usb_connect; - if(value == false) - m_ledcontrol->option(HG_LedOption::HG_WHITE_ON,300); - return is_usb_connect = value; -} - -bool MotorManager::GetOrSetSleepFlag(bool isGet,bool value){ - if(isGet) - return is_sleeping; - if(value == false) - { - if(!(m_sensormonitor->Is_ConverOpen()||m_sensormonitor->Is_Jam())) - { - if(!m_sensormonitor->Is_PaperOn()) - m_motorcontrol->MotorRun(MotorControl::MotorOption::CZ_Reset); - m_ledcontrol->option(HG_WHITE_ON,0); - } - else{ - if(m_sensormonitor->Is_ConverOpen()) - m_ledcontrol->option(HG_RED_ON,300); - else - m_ledcontrol->option(HG_RED_ON,0); - } - } - else - is_autopaper = false; - if(mb_ev_cb_) - mb_ev_cb_(value ? SCANNER_STATUS_SLEEPING : SCANNER_STATUS_WAKED_UP); - - return is_sleeping = value; -} - -void MotorManager::set_capture(std::shared_ptr cap) -{ - m_cap = cap; -} -std::shared_ptr MotorManager::regs() -{ - return nullptr; -} -int MotorManager::os_mode(){ - return 0; -} -bool MotorManager::paper_ready(){ - return m_sensormonitor->Is_PaperOn(); -} -void MotorManager::clear_error(){ - mb_error = 0; -} - -void MotorManager::start(){ - is_motor_run = true; - m_papperout_time = std::chrono::steady_clock::now(); - m_motorcontrol->MotorRun(MotorControl::MotorOption::ZZ_Forward); - m_motorcontrol->MotorRun(MotorControl::MotorOption::CZ_Forward); - GetorSetSysClassValue(false,HG_PWM_FAN,true); - GetorSetSysClassValue(false,HG_MOTOR_FAN,true); - m_ledcontrol->option(HG_WHITE_ON,0); -} -void MotorManager::stop(){ - is_motor_run = false; - m_motorcontrol->MotorRun(MotorControl::MotorOption::CZ_Stop); - m_motorcontrol->MotorRun(MotorControl::MotorOption::ZZ_Stop); - GetorSetSysClassValue(false,HG_PWM_FAN,false); - GetorSetSysClassValue(false,HG_MOTOR_FAN,false); -} -bool MotorManager::wait_paper_out(int timeout_ms){ - return cv_paperout.wait(timeout_ms); -} -bool MotorManager::wait_paper_in(int timeout_ms){ - bool ret = cv_paperin.wait(timeout_ms); - std::cout<<"wait_paper_in timeout:"<MotorRun(MotorControl::MotorOption::CZ_Pause); - return ret; -} -void MotorManager::pick_paper(){ - m_motorcontrol->MotorRun(MotorControl::MotorOption::CZ_Forward); -} - -void MotorManager::stop_pick_paper(){ - m_motorcontrol->MotorRun(MotorControl::MotorOption::CZ_Pause); -} - -bool MotorManager::is_scanning(){ - return false; -} -bool MotorManager::is_jam(){ - return GetorSetSysClassValue(true,"/sys/class/gpio/gpio54/value",true); -} -int MotorManager::paper_counter(){ - return -1; -} -bool MotorManager::set_long_paper(bool enable){ - return false; -} -bool MotorManager::set_double_inpect(bool enable){ - if(enable) - //system("echo 1 > /sys/class/gpio/gpio139/value"); - GetorSetSysClassValue(false,"/sys/class/gpio/gpio139/value",true); - else - //system("echo 0 > /sys/class/gpio/gpio139/value"); - GetorSetSysClassValue(false,"/sys/class/gpio/gpio139/value",false); - return true; -} -bool MotorManager::set_staple_inpect(bool enable){ - return false; -} -bool MotorManager::set_auto_paper(bool enable){ - is_autopaper = enable; - return false; -} -bool MotorManager::set_color_mode(int mode){ - return false; -} - -int MotorManager::get_speed_mode(){ - return -1; -} - -bool MotorManager::set_speed_mode(int mode,int dpi,int iscolor){ - m_motorcontrol->setczspeed(mode,dpi,iscolor); - m_motorcontrol->setzzspeed(mode,dpi,iscolor); - return true; -} -bool MotorManager::set_screw_inpect(bool enable){ - return false; -} -bool MotorManager::get_screw_inpect(){ - return false; -} -bool MotorManager::set_screw_level(int level){ - return false; -} -int MotorManager::get_screw_level(){ - return -1; -} - -bool MotorManager::read(unsigned int addr, unsigned int &val){ - return false; -} -bool MotorManager::write(unsigned int addr, unsigned int val){ - return false; -} -bool MotorManager::set_cuospeed(unsigned int speed,uint dpi,uint iscolor){ - m_motorcontrol->setczspeed(speed,dpi,iscolor); - return true; -} -void MotorManager::set_callbacks(MotorBoardGlue glue){ - m_glue = glue; -} -bool MotorManager::get_keeplastpaper(){ - return false; -} -void MotorManager::motor_reset(){ - m_motorcontrol->MotorRun(MotorControl::CZ_Reset); -} - -void MotorManager::pincall(int value){ - if(mb_ev_cb_) - { - mb_ev_cb_(IMotorBoard::scanner_status_from_raw(value)); - } - if(is_sleeping || !is_usb_connect) - return; - printf("\npin call value %d",value); - if(value == 1){ - cv_paperin.notify_all(); - if(std::chrono::duration(std::chrono::steady_clock::now() - m_papperout_time).count() < 60) - m_glue.m_error_call?m_glue.m_error_call(0x40000):void(0); - printf("\n-------------- paper out time %f ---------------------------",std::chrono::duration(std::chrono::steady_clock::now() - m_papperout_time).count()); - m_papperout_time = std::chrono::steady_clock::now(); - } - else if(value == 0){ - cv_paperout.notify_all(); - m_papperout_time = std::chrono::steady_clock::now(); - } - if(value &0x24) - { - if(m_glue.m_error_call) - m_glue.m_error_call(value); - cv_paperin.notify_all(); - cv_paperout.notify_all(); - - } - if(value == 0x20) - { - this->stop(); - set_double_inpect(false); - } - if(value == 4 && is_converopen()) - m_ledcontrol->option(HG_RED_ON,300); - if(value ==0x4000000 && !is_motor_run) - { - f_motorreset = std::async(std::launch::async,[&](){ - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - if(is_usb_connect && !is_converopen() && (!paper_ready())) - motor_reset(),printf("\n conver reset"); - }); - printf("\n conver ******************************"); - if(is_jam()) - m_ledcontrol->option(HG_RED_ON,0); - else if(!is_usb_connect) - m_ledcontrol->option(HG_WHITE_ON,500); - else - m_ledcontrol->option(HG_WHITE_ON,0); - } - if(is_autopaper && value == 0x2000000 && !is_motor_run) - { - printf("\n ---------------------------------------------------"); - autopaper_state_change = true; - autopaperthread.enqueue([&]{ - StopWatch sw; - while (sw.elapsed_ms()<1000) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - if(!autopaper_state_change) - return; - } - m_glue.m_auto_paper(true); - printf("\n -----------------m_glue.m_auto_paper(true);----------------------------------"); - }); - } - if(is_autopaper && value == 2 && !is_motor_run) - { - autopaper_state_change = false; - } - if(value == 2){ - if(is_motor_run == false && is_converopen() == false && is_jam() == false && m_ledcontrol->get_state() == HG_LedOption::HG_RED_ON) - { - m_ledcontrol->option(HG_WHITE_ON,0); - if(mb_error == 8 || mb_error == 79 || mb_error == 82) - motor_reset(),mb_error = 0; - } - } -} -bool MotorManager::is_converopen() -{ - return m_sensormonitor->Is_ConverOpen(); -} - -void MotorManager::LedControlOption(HG_LedOption option,uint32_t time){ - m_ledcontrol?m_ledcontrol->option(option,time):void(1); -} - -void MotorManager::clean_paper_road(){ - set_speed_mode(1,2,0); - StopWatch sw; - m_motorcontrol->MotorRun(MotorControl::MotorOption::ZZ_Forward); - std::this_thread::sleep_for(std::chrono::milliseconds(1500)); - bool b_clean_ = false; - while(sw.elapsed_s() < 5) - { - if(!is_jam()) - { - b_clean_ = true; - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(700)); - } - m_motorcontrol->MotorRun(MotorControl::MotorOption::ZZ_Stop); - if(is_sleeping || !is_usb_connect) - return; - if(is_motor_run == false && is_converopen() == false && is_jam() == false && m_ledcontrol->get_state() == HG_LedOption::HG_RED_ON || b_clean_) - { - m_ledcontrol->option(HG_WHITE_ON,0); - } -} - -bool MotorManager::GetorSetSysClassValue(bool isGet,std::string path,bool value){ - if(isGet) - { - FILE *fp = fopen(path.c_str(),"r"); - if(fp != NULL) - { - fscanf(fp,"%d",&value); - fclose(fp); - return value; - } - return false; - } - else{ - FILE *fp = fopen(path.c_str(),"w"); - if(fp != NULL) - { - fprintf(fp,"%d",value); - fclose(fp); - return true; - } - return false; - } -} \ No newline at end of file diff --git a/device/gxx-linux/motorboard/motormanager.h b/device/gxx-linux/motorboard/motormanager.h deleted file mode 100644 index 1352e8e..0000000 --- a/device/gxx-linux/motorboard/motormanager.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once -#include "Imotorboard.h" -#include "autoevent.hpp" - -const std::string HG_PWM_FAN = "/sys/class/fv_en_class/fv_en/pwm_fan"; -const std::string HG_MOTOR_FAN = "/sys/class/fv_en_class/fv_en/motor_fan"; - -class MotorControl; -class SensorMonitor; -class LedControl; -enum HG_LedOption : uint8_t; - -class MotorManager : public IMotorBoard -{ -public: - MotorManager(); - virtual ~MotorManager(); - void start() override; - void stop() override; - void clear_error() override; - void pick_paper() override; - void stop_pick_paper() override; - int os_mode() override; - bool paper_ready() override; - bool is_converopen() override; - bool is_scanning() override; - bool is_jam() override; - int paper_counter() override; - bool set_long_paper(bool enable) override; - bool set_double_inpect(bool enable) override; - bool set_staple_inpect(bool enable) override; - bool set_auto_paper(bool enable) override; - bool set_color_mode(int mode) override; - int get_speed_mode() override; - bool set_speed_mode(int mode,int dpi,int iscolor) override; - bool set_screw_inpect(bool enable) override; - bool get_screw_inpect() override; - bool set_screw_level(int level) override; - int get_screw_level() override; - bool wait_paper_out(int timeout_ms) override; - bool wait_paper_in(int timeout_ms) override; - bool read(unsigned int addr, unsigned int &val) override; - bool write(unsigned int addr, unsigned int val) override; - bool set_cuospeed(unsigned int speed,uint dpi,uint iscolor) override; - void set_callbacks(MotorBoardGlue glue) override; - bool get_keeplastpaper() override; - std::shared_ptr regs() override; - void set_capture(std::shared_ptr cap) override; - void motor_reset() override; - bool GetOrSetUsbConnectFlag(bool isGet,bool value); - bool GetOrSetSleepFlag(bool isGet,bool value); - void LedControlOption(HG_LedOption option,uint32_t time) override; - void clean_paper_road() override; -private: - void pincall(int value); - bool GetorSetSysClassValue(bool isGet,std::string path,bool value); - std::unique_ptr m_motorcontrol; - std::unique_ptr m_sensormonitor; - std::unique_ptr m_ledcontrol; - MotorBoardGlue m_glue; - volatile bool is_usb_connect; - volatile bool is_sleeping; - volatile bool is_autopaper; - volatile bool is_motor_run; - volatile bool autopaper_state_change; - std::shared_ptr m_cap; - ThreadPool autopaperthread; - AutoSemaphore cv_paperin; - AutoSemaphore cv_paperout; - std::future f_motorreset; - std::chrono::steady_clock::time_point m_papperout_time; -}; diff --git a/device/gxx-linux/motorboard/opcode.h b/device/gxx-linux/motorboard/opcode.h new file mode 100644 index 0000000..cf0ad91 --- /dev/null +++ b/device/gxx-linux/motorboard/opcode.h @@ -0,0 +1,142 @@ +/******************************************************************* +* Copyright (c) 2011 -2021 Anlogic Inc. + * The Software is distributed in source code form and is open to + * re-distribution and modification where applicable +*******************************************************************/ + + +#ifndef OPCODE_H +#define OPCODE_H + + +#define AJE_DEBUG + + + +// SVF OpCode +#define UNKNOWN 0x00 +#define TRST 0x01 +#define ON 0x02 +#define OFF 0x03 +#define STATE 0x04 +#define ENDIR 0x05 +#define ENDDR 0x06 +#define FREQUENCY 0x07 +#define HZ 0x08 +#define TDR 0x09 +#define TIR 0x0A +#define HDR 0x0B +#define HIR 0x0C +#define SDR 0x0D +#define SIR 0x0E +#define TDI 0x0F +#define TDO 0x10 +#define MASK 0x11 +#define SMASK 0x12 +#define RUNTEST 0x13 +#define TCK 0x14 +#define ENDCMD 0x15 +#define LEFTPAREN 0x16 +#define CONTINUE 0x17 +#define WAIT 0x18 +#define XSDR 0x19 +#define XTDI 0x1A +#define XTDO 0x1B +#define RSDR 0x1C /* It means two SDRs and TDI data of second SDR is the same as TDO of first SDR */ +#define HEADER 0x20 /* Add the specified header to AJE file */ +#define COMMENT 0x21 /* Write comments in SVF file into AJE file */ +#define SETFLOW 0x22 /* Change the flow control register. */ +#define RESETFLOW 0x23 /* Clear the flow control register. */ + +#define LOOP 0x24 +#define ENDLOOP 0x25 + +// Header +#define FILECRC 0x61 +#define MEM 0x62 // The maximum memory needed to allocate in order hold one row of data. +#define ENDFILE 0x7F // End of the file +#define BEGINLINE 0x5E // Begining of line +#define ENDLINE 0x24 // End of line + +// JTAG OpCode +#define RESET 0x00 +#define IDLE 0x01 +#define IRSHIFT 0x02 +#define DRSHIFT 0x03 +#define DRPAUSE 0x04 +#define IRPAUSE 0x05 +#define DRSELECT 0x06 +#define IRSELECT 0x07 +#define DRCAPTURE 0x08 +#define IRCAPTURE 0x09 +#define DREXIT1 0x10 +#define IREXIT1 0x11 +#define DREXIT2 0x12 +#define IREXIT2 0x13 +#define DRUPDATE 0x14 +#define IRUPDATE 0x15 + +// Flow control register bit definitions. +// A set bit indicates that the register currently exhibits the corresponding mode. +#define INTEL_PRGM 0x0001 /* Intelligent programming is in effect. */ +#define CASCADE 0x0002 /* Currently splitting large SDR. */ +#define REPEATLOOP 0x0008 /* Currently executing a repeat loop. */ +#define SHIFTRIGHT 0x0080 /* The next data stream needs a right shift. */ +#define SHIFTLEFT 0x0100 /* The next data stream needs a left shift. */ +#define VERIFYUES 0x0200 /* Continue if fail is in effect. */ + + +// Vendor Code +#define VENDOR 0x56 +#define ANLOGIC 0x01 +#define XILINX 0x02 +#define ALTERA 0x03 +#define LATTICE 0x04 + +// Mode Code +#define COMP_MODE 0xF1 // compress mode +#define FULL_MODE 0xF2 // full mode + +// SIR Command +#define BYPASS 0xFF +#define SAMPLE 0x05 +#define IDCODE_PUB 0x06 +#define IDCODE_PUB_2 0xE0 + +// Reading IO Status +#define LINE_MAX_SIZE 1000 /* max size of a line when reading svf file */ +#define DATA_MAX_SIZE 300 /* max size of tdi/tdo/mask hex str in svf file */ + +// return type +#define AJE_OK 0 +#define AJE_WARNING -1 +#define AJE_ERROR -2 +#define AJE_FILE_OPEN_FAIL -6 +#define AJE_FILE_INVALID -7 +#define AJE_INVALID_COMMAND -10 +#define AJE_INVALID_VALUE -11 +#define AJE_INVALID_TAP_STATE -12 +#define AJE_TRANSFER_FAIL -16 +#define AJE_VERIFY_FAIL -17 + +/* TAP STATE Enumerate */ +enum TAP_STATE { + TAP_RESET = 0, /* Initialization state */ + TAP_IDLE = 1, + TAP_DRSELECT = 2, /* DR STATE: 2~8 */ + TAP_DRCAPTURE = 3, + TAP_DRSHIFT = 4, + TAP_DREXIT1 = 5, + TAP_DRPAUSE = 6, + TAP_DREXIT2 = 7, + TAP_DRUPDATE = 8, + TAP_IRSELECT = 9, /* IR STATE: 9~15 */ + TAP_IRCAPTURE = 10, + TAP_IRSHIFT = 11, + TAP_IREXIT1 = 12, + TAP_IRPAUSE = 13, + TAP_IREXIT2 = 14, + TAP_IRUPDATE = 15, +}; + +#endif // OPCODE_H diff --git a/device/gxx-linux/motorboard/sensormonitor.cpp b/device/gxx-linux/motorboard/sensormonitor.cpp deleted file mode 100644 index 09d9ac1..0000000 --- a/device/gxx-linux/motorboard/sensormonitor.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "sensormonitor.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -SensorMonitor::SensorMonitor(std::function callback):m_callback(callback), - _C6(54),//扫描传感器 - _A4(36),//有无纸传感器 - _C7(55),//开盖传感器 - Double_out0(137)//超声波传感器 -{ - _C6.setDirection(Gpio::in); - _A4.setDirection(Gpio::in); - _C7.setDirection(Gpio::in); - Double_out0.setDirection(Gpio::in); - _C7.setEdge(Gpio::both); - _A4.setEdge(Gpio::both); - _C6.setEdge(Gpio::both); - Double_out0.setEdge(Gpio::rising); - is_paperon = _A4.getValue() == Gpio::GpioLevel::High ? false : true; - is_converopen = _C7.getValue() == Gpio::GpioLevel::High ? false : true; - is_jam = _C6.getValue() == Gpio::GpioLevel::High? true : false; - b_monitor = true; - m_monitor = std::thread(&SensorMonitor::monitor,this); -} - -SensorMonitor::~SensorMonitor() -{ - b_monitor =false; - if(m_monitor.joinable()) - m_monitor.join(); -} -bool SensorMonitor::Is_PaperOn() -{ - return is_paperon; -} - -bool SensorMonitor::Is_ConverOpen() -{ - return is_converopen; -} - -bool SensorMonitor::Is_Jam() -{ - return is_jam; -} - -void SensorMonitor::monitor(){ - pollfd fds[4]{}; - fds[0].fd = open(_C6.getValuePath().c_str(),O_RDONLY); - fds[1].fd = open(_A4.getValuePath().c_str(),O_RDONLY); - fds[2].fd = open(_C7.getValuePath().c_str(),O_RDONLY); - fds[3].fd = open(Double_out0.getValuePath().c_str(),O_RDONLY); - int ret=0; - char buf[8]{}; - int num =0; - num = read(fds[0].fd, buf, 8); - num = read(fds[1].fd, buf, 8); - num = read(fds[2].fd, buf, 8); - num = read(fds[3].fd, buf, 8); - while(b_monitor) - { - ret = poll(fds,4,1000); - if(ret>0) - { - if(fds[0].revents) - { - if(ret = readfile(fds[0].fd,num,buf)){ - if(m_callback) - m_callback(true); - is_jam = true; - } - else{ - if(m_callback) - m_callback(false); - is_jam = false; - } - printf("\n 扫描传感器 %d ",ret); - } - if(fds[1].revents) - { - if(readfile(fds[1].fd,num,buf)){ - is_paperon = false; - m_callback(2); - } - else{ - is_paperon = true; - m_callback(0x2000000); - } - printf("\n 有无纸传感器 %d ",!is_paperon); - } - if(fds[2].revents) - { - if(readfile(fds[2].fd,num,buf)){ - is_converopen = false; - m_callback(0x4000000); - } - else{ - is_converopen = true; - m_callback(4); - } - printf("\n 开盖传感器 %d ",!is_converopen); - } - if(fds[3].revents) - { - if(ret = readfile(fds[3].fd,num,buf)){ - m_callback(0x20); - } - printf("\n 双张 %d ",ret); - } - } - } -} -int SensorMonitor::readfile(int fd,int num , char* buf){ - lseek(fd, 0, SEEK_SET); - num = read(fd, buf, 8); - buf[num - 1] = '\0'; - return atoi(buf); -} \ No newline at end of file diff --git a/device/gxx-linux/motorboard/sensormonitor.h b/device/gxx-linux/motorboard/sensormonitor.h deleted file mode 100644 index ee9e924..0000000 --- a/device/gxx-linux/motorboard/sensormonitor.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "Gpio.h" -#include -#include -#include - -class SensorMonitor -{ -public: - SensorMonitor(std::function callback); - ~SensorMonitor(); - bool Is_PaperOn(); - bool Is_ConverOpen(); - bool Is_Jam(); -private: - void monitor(); - int readfile(int fd,int num , char* buf); - Gpio _C6; - Gpio _A4; - Gpio _C7; - Gpio Double_out0; - std::thread m_monitor; - std::function m_callback; - volatile bool b_monitor; - volatile bool is_converopen; - volatile bool is_paperon; - volatile bool is_jam; - -}; \ No newline at end of file diff --git a/device/gxx-linux/motorboard/vec.cpp b/device/gxx-linux/motorboard/vec.cpp new file mode 100644 index 0000000..9562a47 --- /dev/null +++ b/device/gxx-linux/motorboard/vec.cpp @@ -0,0 +1,521 @@ +/******************************************************************* + * Copyright (c) 2011 -2021 Anlogic Inc. + * This file is strictly confidential. All rights reserved. +*******************************************************************/ + +/*********************************************************************** +Filename: vec.c +Description: generate vec +Log: initial version, July 2019 + ***********************************************************************/ + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include "Jtag.h" + +#include "opcode.h" + + +/* global variables about hdr/hir/tdr/tir */ +unsigned int g_hdr_size = 0; +unsigned int g_hir_size = 0; +unsigned int g_tdr_size = 0; +unsigned int g_tir_size = 0; + +unsigned char* g_hdr_data = NULL; +unsigned char* g_hir_data = NULL; +unsigned char* g_tdr_data = NULL; +unsigned char* g_tir_data = NULL; + +static Jtag jtag_burning; + +/* function declared in ajeutil.c */ +extern int Anlogic_GetBit(unsigned char* data, int id); +extern void Anlogic_SetBit(unsigned char* data, int id, int val); +extern unsigned char Anlogic_ReverseChar(unsigned char byte); + + +/* Function forward declaration */ +void Anlogic_WritePulseTck(void); + +/* Tap Opcode To TAP_STATE */ +enum TAP_STATE Anlogic_TapState(unsigned char opcode) { + enum TAP_STATE state = TAP_RESET; + switch (opcode) { + case RESET: state = TAP_RESET; break; + case IDLE: state = TAP_IDLE; break; + case DRSELECT: state = TAP_DRSELECT; break; + case DRCAPTURE: state = TAP_DRCAPTURE; break; + case DRSHIFT: state = TAP_DRSHIFT; break; + case DREXIT1: state = TAP_DREXIT1; break; + case DRPAUSE: state = TAP_DRPAUSE; break; + case DREXIT2: state = TAP_DREXIT2; break; + case DRUPDATE: state = TAP_DRUPDATE; break; + case IRSELECT: state = TAP_IRSELECT; break; + case IRCAPTURE: state = TAP_IRCAPTURE; break; + case IRSHIFT: state = TAP_IRSHIFT; break; + case IREXIT1: state = TAP_IREXIT1; break; + case IRPAUSE: state = TAP_IRPAUSE; break; + case IREXIT2: state = TAP_IREXIT2; break; + case IRUPDATE: state = TAP_IRUPDATE; break; + default: + printf("Error: Illegal tap state opcode %u\n", (unsigned int)opcode); + } + return state; +} + +/* TAP_STATE to TapState String */ +const char* Anlogic_TapState2Str(enum TAP_STATE tap_state) { +#define X(_w) if (tap_state == TAP_ ## _w) return #_w + X(RESET); + X(IDLE); + X(DRSELECT); + X(DRCAPTURE); + X(DRSHIFT); + X(DREXIT1); + X(DRPAUSE); + X(DREXIT2); + X(DRUPDATE); + X(IRSELECT); + X(IRCAPTURE); + X(IRSHIFT); + X(IREXIT1); + X(IRPAUSE); + X(IREXIT2); + X(IRUPDATE); +#undef X + return "TapState2Str: unkown state"; +} + +static enum TAP_STATE cur_tap_state = TAP_RESET; /* current tap state */ +static enum TAP_STATE end_dr_state = TAP_IDLE; /* the tap state that device goes after sdr */ +static enum TAP_STATE end_ir_state = TAP_IDLE; /* the tap state that device goes after sir */ + + +/* Tap State Transistions */ +int Anlogic_TapTransist(enum TAP_STATE state) { + int id = 0; + int count = 0; + +// printf("Anlogic_TapTransist start...\n"); + if (cur_tap_state == state && state == TAP_RESET) { + for (id = 0; id < 6; ++id) { + jtag_burning.TMS_Wr(1); + + Anlogic_WritePulseTck(); + } +// printf("Anlogic_TapTransist 107 end...\n"); + return 0; + } + + while (cur_tap_state != state) { + switch (cur_tap_state) { + case TAP_RESET: + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_IDLE; + break; + case TAP_IDLE: + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_DRSELECT; + break; + /* DR STATE Transistion */ + case TAP_DRSELECT: + if (state >= TAP_IRSELECT || state == TAP_RESET) { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_IRSELECT; + } else { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_DRCAPTURE; + } + break; + case TAP_DRCAPTURE: + if (state == TAP_DRSHIFT) { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_DRSHIFT; + } else { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_DREXIT1; + } + break; + case TAP_DRSHIFT: + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_DREXIT1; + break; + case TAP_DREXIT1: + if (state == TAP_DRPAUSE) { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_DRPAUSE; + } else { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_DRUPDATE; + } + break; + case TAP_DRPAUSE: + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_DREXIT2; + break; + case TAP_DREXIT2: + if (state == TAP_DRSHIFT) { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_DRSHIFT; + } else { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_DRUPDATE; + } + break; + case TAP_DRUPDATE: + if (state == TAP_IDLE) { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_IDLE; + } else { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_DRSELECT; + } + break; + /* IR STATE Transistion */ + case TAP_IRSELECT: + if (state == TAP_RESET) { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_RESET; + } else { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_IRCAPTURE; + } + break; + case TAP_IRCAPTURE: + if (state == TAP_IRSHIFT) { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_IRSHIFT; + } else { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_IREXIT1; + } + break; + case TAP_IRSHIFT: + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_IREXIT1; + break; + case TAP_IREXIT1: + if (state == TAP_IRPAUSE) { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_IRPAUSE; + } else { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_IRUPDATE; + } + break; + case TAP_IRPAUSE: + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_IREXIT2; + break; + case TAP_IREXIT2: + if (state == TAP_IRSHIFT) { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_IRSHIFT; + } else { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_IRUPDATE; + } + break; + case TAP_IRUPDATE: + if (state == TAP_IDLE) { + jtag_burning.TMS_Wr(0); + cur_tap_state = TAP_IDLE; + } else { + jtag_burning.TMS_Wr(1); + cur_tap_state = TAP_IRSELECT; + } + break; + default: + printf("Error: invalid tap sate.\n"); + return -1; + } + Anlogic_WritePulseTck(); + + if (++count > 10) { + printf("Error: Loop in Tap Transistion."); + return -1; + } + } + jtag_burning.TDI_Wr(0); +// printf("Anlogic_TapTransist 240 end...\n"); + return 0; +} + +/* Init function, set current tap state to reset */ +void Anlogic_Init(void) { + cur_tap_state = TAP_RESET; + Anlogic_TapTransist(TAP_RESET); +} + +/* set the tap state that deevice goes after sdr */ +void Anlogic_SetEndDRState(enum TAP_STATE end_st) { + end_dr_state = end_st; +#ifdef AJE_DEBUG + printf("ENDDR %s;\n", Anlogic_TapState2Str(end_st)); +#endif +} + +/* set the tap state that deevice goes after sir */ +void Anlogic_SetEndIRState(enum TAP_STATE end_st) { + end_ir_state = end_st; +#ifdef AJE_DEBUG + printf("ENDIR %s;\n", Anlogic_TapState2Str(end_st)); +#endif +} + +/* Send HIR/HDR/TIR/TDR data to device */ +void Anlogic_SendBypassData(unsigned int op_code) { + unsigned char* data = NULL; + unsigned int size = 0; + unsigned int index = 0; + unsigned int bit = 0; + + switch (op_code) { + case HIR: size = g_hir_size; data = g_hir_data; break; + case HDR: size = g_hdr_size; data = g_hdr_data; break; + case TIR: size = g_tir_size; data = g_tir_data; break; + case TDR: size = g_tdr_size; data = g_tdr_data; break; + default: break; + } + + /* no value set, use default */ + if (data == NULL) { + bit = (op_code == HIR || op_code == TIR) ? 1 : 0; + } + + for (index = 0; index < size-1; ++index) { + if (data != NULL) { + bit = Anlogic_GetBit(data, index); + } + jtag_burning.TDI_Wr(bit); + Anlogic_WritePulseTck(); + } + + bit = Anlogic_GetBit(data, index); + jtag_burning.TDI_Wr(bit); +} + +/* Send TDI data to device */ +int Anlogic_SendData(unsigned char* tdi_data, unsigned int bin_size, int cascade) { + unsigned int index = 0; + unsigned int bit = 0; + + for (index = 0; index < bin_size-1; ++index) { + bit = Anlogic_GetBit(tdi_data, index); + jtag_burning.TDI_Wr(bit); + Anlogic_WritePulseTck(); + } + + bit = Anlogic_GetBit(tdi_data, index); + jtag_burning.TDI_Wr(bit); + + if (cascade == 1) { + Anlogic_WritePulseTck(); + } + return 0; +} + +/* Send TDI data and read TDO, Verify */ +int Anlogic_ReadData(unsigned char* tdi_data, unsigned char* tdo_data, unsigned char* mask, unsigned int data_size, int cascade) { + unsigned int index = 0; + int tdi_bit = 0; + int tdo_bit = 0; + int mask_bit = 0; + + for (index = 0; index < data_size-1; ++index) { + tdi_bit = Anlogic_GetBit(tdi_data, index); + tdo_bit = Anlogic_GetBit(tdo_data, index); + mask_bit = Anlogic_GetBit(mask, index); + + if (mask_bit == 1 && tdo_bit != jtag_burning.TDO_RD()) { + return AJE_VERIFY_FAIL; + } + + jtag_burning.TDI_Wr(tdi_bit); + Anlogic_WritePulseTck(); + } + + tdi_bit = Anlogic_GetBit(tdi_data, index); + tdo_bit = Anlogic_GetBit(tdo_data, index); + mask_bit = Anlogic_GetBit(mask, index); + + if (mask_bit == 1 && tdo_bit != jtag_burning.TDO_RD()) { + return AJE_VERIFY_FAIL; + } + jtag_burning.TDI_Wr(tdi_bit); + + if (cascade == 1) { + Anlogic_WritePulseTck(); + } + + return AJE_OK; +} + +/* Send TDI Data and Save TDO */ +int Anlogic_SaveData(unsigned char* tdi_data, unsigned int data_size, unsigned char** tdo_data) { + unsigned int index = 0; + unsigned int tdi_bit = 0; + unsigned int tdo_bit = 0; + + for (index = 0; index < data_size-1; ++index) { + tdo_bit = jtag_burning.TDO_RD(); + Anlogic_SetBit(*tdo_data, index, tdo_bit); + tdi_bit = Anlogic_GetBit(tdi_data, index); + jtag_burning.TDI_Wr(tdi_bit); + Anlogic_WritePulseTck(); + } + tdo_bit = jtag_burning.TDO_RD(); + Anlogic_SetBit(*tdo_data, index, tdo_bit); + tdi_bit = Anlogic_GetBit(tdi_data, index); + jtag_burning.TDI_Wr(tdi_bit); + + return AJE_OK; +} + +/* Process SIR/SDR */ +int Anlogic_ProcessShiftCmd(unsigned int op_code, unsigned int cascade, unsigned int read, unsigned int data_size, + unsigned char* tdi_data, unsigned char* tdo_data, unsigned char* mask) { + int rtn_val = AJE_OK; + // process header data + switch (op_code) { + case SIR: + if (cascade != 1) { + Anlogic_TapTransist(TAP_IRSHIFT); + if (g_hir_size > 0) { + Anlogic_SendBypassData(HIR); + Anlogic_WritePulseTck(); + } + } + break; + case SDR: + if (cascade != 1) { + Anlogic_TapTransist(TAP_DRSHIFT); + if (g_hdr_size > 0) { + Anlogic_SendBypassData(HDR); + Anlogic_WritePulseTck(); + } + } + break; + default: + break; + } + + if (read == 1) { + rtn_val =Anlogic_SaveData(tdi_data, data_size, &tdo_data); + } else if (mask == NULL) { + rtn_val =Anlogic_SendData(tdi_data, data_size, cascade); + } else { + rtn_val =Anlogic_ReadData(tdi_data, tdo_data, mask, data_size, cascade); + } + + // process tailer data + switch (op_code) { + case SIR: + if (cascade != 1) { + if (g_tir_size > 0) { + Anlogic_WritePulseTck(); + Anlogic_SendBypassData(TIR); + } + Anlogic_TapTransist(end_ir_state); + } + break; + case SDR: + if (cascade != 1) { + if (g_tdr_size > 0) { + Anlogic_WritePulseTck(); + Anlogic_SendBypassData(TDR); + } + Anlogic_TapTransist(end_dr_state); + } + break; + default: + break; + } + + return rtn_val; +} + +/* process single sir command, do not use bypass data (hir/tir) */ +int Anlogic_ExeSirCommand(unsigned char command, int cur_lvl, int total_lvl) { + int rtn_val = AJE_OK; + unsigned char* tdi_data = NULL; + int id = 0; + Anlogic_TapTransist(TAP_IRSHIFT); + + tdi_data = (unsigned char*)calloc((total_lvl*8+1), sizeof(unsigned char)); + for(id = 0; id < total_lvl; ++id) { + if (id == (total_lvl - cur_lvl)) { + tdi_data[id] = Anlogic_ReverseChar(command); + } else { + tdi_data[id] = 0xFF; + } + } + rtn_val = Anlogic_SendData(tdi_data, total_lvl*8, 0 /*cascade*/); + Anlogic_TapTransist(end_ir_state); + + return rtn_val; +} + +/* process sdr command, do not use bypass data (hdr/tdr) */ +int Anlogic_ExeSdrCommand(unsigned int bit_size, int cur_lvl, int total_lvl, + unsigned char* tdi_data, unsigned char* tdo_data) { + int rtn_val = AJE_OK; + int head_num = total_lvl - cur_lvl; + int tailer_num = cur_lvl-1; + int id = 0; + unsigned int byte_size = (bit_size + 7)/8; + + Anlogic_TapTransist(TAP_DRSHIFT); + if (head_num > 0) { + for (id = 0; id < head_num; ++id) { + jtag_burning.TDI_Wr(0); + Anlogic_WritePulseTck(); + } + } + + if (tdi_data == NULL) { + tdi_data = (unsigned char*)calloc((byte_size+1), sizeof(unsigned char)); + } + + if (tdo_data == NULL) { + rtn_val = Anlogic_SendData(tdi_data, bit_size, 0 /*cascade*/); + } else { /* read and save tdo readback data */ + rtn_val = Anlogic_SaveData(tdi_data, bit_size, &tdo_data /*cascade*/); + } + + if (tailer_num > 0) { + for (id = 0; id < tailer_num; ++id) { + Anlogic_WritePulseTck(); + jtag_burning.TDI_Wr(0); + } + } + + Anlogic_TapTransist(end_dr_state); + return rtn_val; +} + +/* process runtest num tck */ +void Anlogic_ProcessRunTestTck(int num) { + volatile int i = 0; + jtag_burning.TDI_Wr(0); + jtag_burning.TMS_Wr(0); + for(i = 0; i < num; ++i) { + jtag_burning.TCK_Wr(1); + jtag_burning.TCK_Wr(0); + } +#ifdef AJE_DEBUG + printf("RUNTEST %d TCK;\n", num); +#endif +} + +void Anlogic_WritePulseTck(void) { + static unsigned int i = 0; + jtag_burning.TCK_Wr(1); + jtag_burning.TCK_Wr(0); +} diff --git a/device/gxx-linux/motorboard/xmake.lua b/device/gxx-linux/motorboard/xmake.lua index 6cca12f..141c006 100644 --- a/device/gxx-linux/motorboard/xmake.lua +++ b/device/gxx-linux/motorboard/xmake.lua @@ -4,6 +4,7 @@ target("motorboard") set_kind("static") add_syslinks("pthread") add_files("*.cpp") - add_deps("regs", "motor_run" ,"deviceio", "conf", "applog", "capimage",{public = true}) + add_deps("regs", "deviceio","motorcontroller","keymonitor" ,"conf", "applog", {public = true}) add_includedirs(".", { public = true}) + add_includedirs("../scanner",{public = true}) add_packages("common") \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/IState.h b/device/gxx-linux/motorcontroller/IState.h new file mode 100644 index 0000000..27ee558 --- /dev/null +++ b/device/gxx-linux/motorcontroller/IState.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include +#include +#include "Statedef.h" +#include "BlockingQueue.h" +#include "LCDDisplay.h" + +class IState +{ +public: + IState(/* args */){ + display = std::make_unique(); + } + virtual ~IState(){} + virtual void InitState(int state=0) =0; + virtual IState* OnState(StateInfo state) = 0; + virtual void SetBtnCall(std::function call) = 0; + std::string typeName = "FsmState"; + static void SetConfirmCall(std::function confirmcall) + { + m_confirmcall = confirmcall; + } +private: + static std::function m_confirmcall; +protected: + std::unique_ptr display; +}; + + diff --git a/device/gxx-linux/motorcontroller/Menu.cpp b/device/gxx-linux/motorcontroller/Menu.cpp new file mode 100644 index 0000000..92ad7a0 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Menu.cpp @@ -0,0 +1,51 @@ +#include "Menu.h" + +Menu::Menu(const char *const name,DisType dt) : name_(name) +{ + +} + +Menu::~Menu() +{ + std::cout << "Menu " << name_ << " destroyed" << std::endl; + for (auto &item : menu_items) + { + item.reset(); + } +} + +string Menu::get_name() +{ + return name_; +} + +int Menu::select() +{ + int ret = -1; + int choice; + int count = 0; + + for (auto &item : menu_items) + { + std::cout << item->get_name() << " : " << count++ << std::endl; + } + + if (choice >= 0 && choice <= menu_items.size()) + { + ret = menu_items[choice]->select(); + // if(!ret) + // g_call(); + } + + + count = 0; + choice = 0; + + return ret; +} + +void Menu::add_menu_item(unique_ptr menu_item) +{ + menu_items.push_back(std::move(menu_item)); +} + diff --git a/device/gxx-linux/motorcontroller/Menu.h b/device/gxx-linux/motorcontroller/Menu.h new file mode 100644 index 0000000..4e05781 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Menu.h @@ -0,0 +1,16 @@ +#pragma once +#include "Selectable.h" + +class Menu : public Selectable +{ +private: + std::string name_; + vector> menu_items; + +public: + Menu(const char *const name,DisType dt); + virtual ~Menu(); + virtual string get_name() override; + virtual int select() override; + void add_menu_item(unique_ptr menu_item); +}; \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/MenuComponent.cpp b/device/gxx-linux/motorcontroller/MenuComponent.cpp new file mode 100644 index 0000000..694e9fd --- /dev/null +++ b/device/gxx-linux/motorcontroller/MenuComponent.cpp @@ -0,0 +1,135 @@ +#include "MenuComponent.h" +#include "Menu.h" +#include "Menu_Item.h" +#include "commondef.h" + +MenuComponent::MenuComponent() +{ + if (!m_menu.get()) + m_menu.reset(new Menu("Menu",DisType::Dis_Idel)); + current_distype = DisType::Dis_Idel; + cur_index = 0; +} + +MenuComponent::~MenuComponent() +{ + + if (m_menu.get()) + m_menu.reset(); +} + +void MenuComponent::initmenu() +{ + m_keytable.push_back({0,0,1,DisType::Dis_Idel}); //0 + m_keytable.push_back({6,2,0,DisType::Dis_Set_ClearPaperPass}); //1 + m_keytable.push_back({1,3,7,DisType::Dis_Set_PollPaperIntensity}); //2 +#ifdef G200 + m_keytable.push_back({2,4,11,DisType::Dis_Set_SleepMode}); //3 + m_keytable.push_back({3,5,20,DisType::Dis_Set_TrayPosition}); //4 + m_keytable.push_back({4,6,0,DisType::Dis_Set_Poweroff}); //5 +#else + m_keytable.push_back({2,5,11,DisType::Dis_Set_SleepMode}); //3 + m_keytable.push_back({3,5,20,DisType::Dis_Set_TrayPosition}); //4 + m_keytable.push_back({3,6,0,DisType::Dis_Set_Poweroff}); //5 +#endif + m_keytable.push_back({5,1,0,DisType::Dis_Set_Return});//6 + m_keytable.push_back({10,8,2,DisType::Dis_Set_PollPI_High}); //7 + m_keytable.push_back({7,9,2,DisType::Dis_Set_PollPI_Mid}); //8 + m_keytable.push_back({8,10,2,DisType::Dis_Set_PollPI_Low}); //9 + m_keytable.push_back({9,7,2,DisType::Dis_Set_Item_Return}); //10 + m_keytable.push_back({19,12,3,DisType::Dis_Set_SleepMode_5M}); //11 + m_keytable.push_back({11,13,3,DisType::Dis_Set_SleepMode_10M}); //12 + m_keytable.push_back({12,14,3,DisType::Dis_Set_SleepMode_20M}); //13 + m_keytable.push_back({13,15,3,DisType::Dis_Set_SleepMode_30M}); //14 + m_keytable.push_back({14,16,3,DisType::Dis_Set_SleepMode_1H}); //15 + m_keytable.push_back({15,17,3,DisType::Dis_Set_SleepMode_2H}); //16 + m_keytable.push_back({16,18,3,DisType::Dis_Set_SleepMode_4H}); //17 + m_keytable.push_back({17,19,3,DisType::Dis_Set_SleepMode_NEVER}); //18 + m_keytable.push_back({18,11,3,DisType::Dis_Set_Item_Return});//19 + m_keytable.push_back({23,21,4,DisType::Dis_Set_TrayPosition_High}); //20 + m_keytable.push_back({20,22,4,DisType::Dis_Set_TrayPosition_Mid}); //21 + m_keytable.push_back({21,23,4,DisType::Dis_Set_TrayPosition_Low});//22 + m_keytable.push_back({22,20,4,DisType::Dis_Set_Item_Return});//23 + // if (m_menu.get()) + // { + + // unique_ptr menu_clearpass = std::make_unique("clearpass",DisType::Dis_Set_ClearPaperPass); + // m_menu->add_menu_item(std::move(menu_clearpass)); + + // unique_ptr submenu_feedstrength = std::make_unique("feedstrenth",DisType::Dis_Set_PollPaperIntensity); + // std::unique_ptr feeditemH = std::make_unique("feedhigh",DisType::Dis_Set_PollPI_High); + // std::unique_ptr feeditemM = std::make_unique("feedmid",DisType::Dis_Set_PollPI_Mid); + // std::unique_ptr feeditemL = std::make_unique("feedlow",DisType::Dis_Set_PollPI_Low); + // submenu_feedstrength->add_menu_item(std::move(feeditemH)); + // submenu_feedstrength->add_menu_item(std::move(feeditemM)); + // submenu_feedstrength->add_menu_item(std::move(feeditemL)); + // m_menu->add_menu_item(std::move(submenu_feedstrength)); + + // unique_ptr submenu_sleep = std::make_unique("sleepset",DisType::Dis_Set_SleepMode); + // std::unique_ptr sleep30 = std::make_unique("30min",DisType::Dis_Set_SleepMode_30M); + // std::unique_ptr sleep60 = std::make_unique("60min",DisType::Dis_Set_SleepMode_1H); + // std::unique_ptr sleep120 = std::make_unique("120min",DisType::Dis_Set_SleepMode_2H); + // std::unique_ptr sleepnever = std::make_unique("never",DisType::Dis_Set_SleepMode_NEVER); + // submenu_sleep->add_menu_item(std::move(sleep30)); + // submenu_sleep->add_menu_item(std::move(sleep60)); + // submenu_sleep->add_menu_item(std::move(sleep120)); + // submenu_sleep->add_menu_item(std::move(sleepnever)); + // m_menu->add_menu_item(std::move(submenu_sleep)); + + // unique_ptr submenu_poweroff = std::make_unique("poweroff",DisType::Dis_Set_Poweroff); + // m_menu->add_menu_item(std::move(submenu_poweroff)); + // } +} + +void MenuComponent::select() +{ + if (m_menu.get()) + { + m_menu->select(); + } +} + +void MenuComponent::option(int key) +{ + switch (key) + { +#ifdef G200 + case 85: //Key_Menu + cur_index = m_keytable[cur_index].enter; + break; + case 86: //Key_Left + cur_index = m_keytable[cur_index].up; + break; + case 76: //Key_Right + cur_index = m_keytable[cur_index].down; + break; +#else + case 76: //Key_Menu + cur_index = m_keytable[cur_index].enter; + break; + case 77: //Key_Right + cur_index = m_keytable[cur_index].down; + break; +#endif + default: + break; + } +} + +DisType MenuComponent::getcurtype() +{ + return m_keytable[cur_index].m_type; +} + +void MenuComponent::setcurindex(int x) +{ + if(x < 0 || x >= m_keytable.size()) + return ; + cur_index = x; + printf("\n MenuComponent setcurindex %d",x); +} + +int MenuComponent::getcurindex() +{ + return cur_index; +} \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/MenuComponent.h b/device/gxx-linux/motorcontroller/MenuComponent.h new file mode 100644 index 0000000..606d702 --- /dev/null +++ b/device/gxx-linux/motorcontroller/MenuComponent.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include "Displaydef.h" +class Menu; +class Menu_Item; + +struct keypause{ + int up; + int down; + int enter; + DisType m_type; +}; + +class MenuComponent +{ +private: + /* data */ +public: + MenuComponent(/* args */); + ~MenuComponent(); + void initmenu(); + void select(); + void option(int key); + DisType getcurtype(); + void setcurindex(int x); + int getcurindex(); +private: + + std::shared_ptr m_menu; + DisType current_distype; + std::vector m_keytable; + int cur_index; +}; diff --git a/device/gxx-linux/motorcontroller/Menu_Item.cpp b/device/gxx-linux/motorcontroller/Menu_Item.cpp new file mode 100644 index 0000000..0818e0a --- /dev/null +++ b/device/gxx-linux/motorcontroller/Menu_Item.cpp @@ -0,0 +1,24 @@ +#include "Menu_Item.h" + +Menu_Item::Menu_Item(const char *const name,DisType dt) : name_{name} +{ + +} + +Menu_Item::~Menu_Item() +{ + std::cout<<"Menu_Item Name "<(&MotorController::runloop,this); + auto keycall=[&](int key) + { + auto iter = m_keystats.find((HgBtn)key); + if(iter!=m_keystats.end()) + { + m_msg.Put(iter->second); + } + }; + m_keyMinitor= make_shared(keycall); +} + +MotorController::~MotorController() +{ + + if(m_threadmsgloop.get() && m_threadmsgloop->joinable()) + { + m_bloop = false; + m_threadmsgloop->join(); + m_threadmsgloop.reset(); + } + LOG_TRACE("MotorController ~ctor exit \n"); +} + +void MotorController::runloop() +{ + m_bloop = true; + IState* mtstate = StateManager::GetState(); + m_msg.Put({HGScannerStatus::Mode_Idel,0}); + while (m_bloop) + { + auto msg = m_msg.Take(); + printf("\n msg status = %d ",msg.status); + if(msg.status == HGScannerStatus::Mode_Scan_Start) + mtstate = StateManager::GetState(); + if(msg.status == HGScannerStatus::Mode_Count) + mtstate = StateManager::GetState(msg.value); + if(msg.status == HGScannerStatus::Mode_Set_Key_Manual) + mtstate = StateManager::GetState(); + if(msg.status >= HGScannerStatus::Mode_Error_Jam && msg.status <= HGScannerStatus::Mode_Error_DogEar || msg.status == HGScannerStatus::Mode_Error_FeedError) + mtstate = StateManager::GetState((int)msg.status); + if(msg.status == HGScannerStatus::Mode_Idel) + mtstate = StateManager::GetState(); + //mtstate = mtstate->OnState(msg); + } +} + +void MotorController::PutMsg(StateInfo mode) +{ + m_msg.Put(mode); +} + + +void MotorController::SendMsg() +{ + +} + + diff --git a/device/gxx-linux/motorcontroller/MotorController.h b/device/gxx-linux/motorcontroller/MotorController.h new file mode 100644 index 0000000..48b6864 --- /dev/null +++ b/device/gxx-linux/motorcontroller/MotorController.h @@ -0,0 +1,36 @@ +#pragma once +#include "StateManager.h" +#include "IState.h" +#include "BlockingQueue.h" +#include "keymonitor.h" + +using HgBtn = KeyMonitor::HGKey; + +class MotorController +{ +public: + MotorController(/* args */); + ~MotorController(); + void PutMsg(StateInfo mode); +private: + void runloop(); + void SendMsg(); + void procmsg(); + +private: + std::atomic m_bloop; + BlockingQueue m_msg; + std::shared_ptr m_threadmsgloop; + std::shared_ptr m_keyMinitor; + const std::map m_keystats={ + {HgBtn::Key_Enter,{HGScannerStatus::Mode_Set_Key_Enter,0}}, + {HgBtn::Key_Cancle,{HGScannerStatus::Mode_Set_Key_Back,0}}, + {HgBtn::Key_Count,{HGScannerStatus::Mode_Set_Key_Count,0}}, + {HgBtn::Key_Handle,{HGScannerStatus::Mode_Set_HandMode,0}}, + {HgBtn::Key_DoubleFeed,{HGScannerStatus::Mode_Set_Key_EnDoubleFeed,0}}, + {HgBtn::Key_Left,{HGScannerStatus::Mode_Set_Key_Left,0}}, + {HgBtn::Key_Menu,{HGScannerStatus::Mode_Set_Key_Manual,0}}, + {HgBtn::Key_Right,{HGScannerStatus::Mode_Set_Key_Right,0}}, + {HgBtn::Key_Clear,{HGScannerStatus::Mode_Set_Key_ClearCount,0}} + }; +}; diff --git a/device/gxx-linux/motorcontroller/MotorboardParam.cpp b/device/gxx-linux/motorcontroller/MotorboardParam.cpp new file mode 100644 index 0000000..40337f4 --- /dev/null +++ b/device/gxx-linux/motorcontroller/MotorboardParam.cpp @@ -0,0 +1,176 @@ +#include "MotorboardParam.h" +#include +#include +#include +#include "commondef.h" +#include +MotorboardParam::MotorboardParam(/* args */) +{ +} + +MotorboardParam::~MotorboardParam() +{ +} + +int MotorboardParam::GetOrSetEnableAutomaticControlFeedMode(bool isget,int value){ + std::lock_guard lc(m_setlock); + if(isget) + { + auto js = getjson(); + if(!js[automaticcontrol_feedmode].is_null() && js[automaticcontrol_feedmode].is_number()) + return js[automaticcontrol_feedmode]; + else{ + printf("\nread motorboardparam error : feedmode!!! "); + return 1; + } + } + else{ + auto js = getjson(); + if(!js[automaticcontrol_feedmode].is_null() && js[automaticcontrol_feedmode].is_number()) + { + js[automaticcontrol_feedmode] = value; + savejson(js); + } + return 0; + } +} + +int MotorboardParam::GetOrSetFeedMode(bool isget,int value){ + std::lock_guard lc(m_setlock); + if(isget) + { + auto js = getjson(); + if(!js[feed_mode].is_null() && js[feed_mode].is_number()) + return js[feed_mode]; + else{ + printf("\nread motorboardparam error : feedmode!!! "); + return 1; + } + } + else{ + if(value < 0 || value > 2) + return 0; + auto js = getjson(); + if(!js[feed_mode].is_null() && js[feed_mode].is_number()) + { + js[feed_mode] = value; + savejson(js); + } + return 0; + } +} + +int MotorboardParam::GetOrSetTrayPosition(bool isget,int value){ + std::lock_guard lc(m_setlock); + if(isget) + { + auto js = getjson(); + if(!js[trayposition].is_null() && js[trayposition].is_number()) + return js[trayposition]; + else{ + printf("\nread motorboardparam error : feedmode!!! "); + return 0; + } + } + else{ + if(value < 0 || value > 2) + return 0; + auto js = getjson(); + if(!js[trayposition].is_null() && js[trayposition].is_number()) + { + js[trayposition] = value; + savejson(js); + } + return 0; + } +} + +void MotorboardParam::savejson(json js){ + remove(ParamPath.c_str()); + std::ofstream o(ParamPath); + o << std::setw(4) << js < lc(m_setlock); + json tmp = getjson(); + return json2struct(tmp); +} + +void MotorboardParam::SaveParam(MotorboardParam::MBParam param){ + std::lock_guard lc(m_setlock); + auto tmp = struct2json(param); + savejson(tmp); +} + +json MotorboardParam::getdefaultjson(){ + json m_json; + m_json[feed_mode] = 1; //0 low 1 mid 2 high + m_json[automaticcontrol_feedmode] = 0; + m_json[automaticcontrolfeedmode_threshold] = 0.5; + m_json[trayposition] = 0; + return m_json; +} + +json MotorboardParam::struct2json(MotorboardParam::MBParam param){ + json js; + js[feed_mode] = param.feedmode; //0 low 1 mid 2 high + js[automaticcontrol_feedmode] = param.automaticcontrolfeedmode; + js[automaticcontrolfeedmode_threshold] = param.automaticcontrolfeedmode_threshold; + js[trayposition] = param.trayposition; + return js; +} + +MotorboardParam::MBParam MotorboardParam::json2struct(json js){ + MotorboardParam::MBParam param{0}; + if(js[feed_mode].is_number()) + param.feedmode = js[feed_mode]; + else + param.feedmode = 1; + if(js[automaticcontrol_feedmode].is_number()) + param.automaticcontrolfeedmode = js[automaticcontrol_feedmode]; + else + param.automaticcontrolfeedmode = 0; + if(js[automaticcontrolfeedmode_threshold].is_number_float()) + param.automaticcontrolfeedmode_threshold = js[automaticcontrolfeedmode_threshold]; + else + param.automaticcontrolfeedmode_threshold = 0.5 ; + if(js[trayposition].is_number()) + param.trayposition = js[trayposition]; + else + param.trayposition = 0; + return param; +} + +json MotorboardParam::getjson(){ + if(access(JSON_CORRECTDIR_PATH,0) == -1) + { + auto ret = mkdir(JSON_CORRECTDIR_PATH, 0777); + if (ret != 0) + { + printf("make dir failed .path=%s \n", JSON_CORRECTDIR_PATH); + } + } + if (access(ParamPath.c_str(), F_OK) != 0) + { + auto cfs = getdefaultjson(); + savejson(cfs); + return cfs; + } + std::ifstream i(ParamPath); + auto pos = i.tellg(); + i.seekg(0, std::ios::end); + if (i.tellg() <= 2) + { + auto cfs = getdefaultjson(); + savejson(cfs); + return cfs; + } + i.seekg(pos); + json m_json; + i >> m_json; + i.close(); + return m_json; +} + diff --git a/device/gxx-linux/motorcontroller/MotorboardParam.h b/device/gxx-linux/motorcontroller/MotorboardParam.h new file mode 100644 index 0000000..89374bf --- /dev/null +++ b/device/gxx-linux/motorcontroller/MotorboardParam.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#include +using json = nlohmann::json; + + +class MotorboardParam +{ +private: + const std::string ParamPath ="/usr/local/huago/motorboardparam.json"; + const std::string feed_mode = "feedmode"; + const std::string automaticcontrol_feedmode = "automaticcontrolfeedmode"; + const std::string automaticcontrolfeedmode_threshold = "automaticcontrolfeedmodethreshold"; + const std::string trayposition = "trayposition"; +public: + struct MBParam + { + int feedmode; + int automaticcontrolfeedmode; + float automaticcontrolfeedmode_threshold; + int trayposition; + }; + MotorboardParam(/* args */); + ~MotorboardParam(); + MotorboardParam::MBParam GetParam(); + void SaveParam(MotorboardParam::MBParam param); + int GetOrSetTrayPosition(bool isget,int value); + int GetOrSetFeedMode(bool isget,int value); + int GetOrSetEnableAutomaticControlFeedMode(bool isget,int value); +private: + void savejson(json js); + json struct2json(MotorboardParam::MBParam param); + MotorboardParam::MBParam json2struct(json js); + json getjson(); + json getdefaultjson(); + std::mutex m_setlock; +}; + diff --git a/device/gxx-linux/motorcontroller/Mt_Count.cpp b/device/gxx-linux/motorcontroller/Mt_Count.cpp new file mode 100644 index 0000000..ab206f1 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Count.cpp @@ -0,0 +1,26 @@ +#include "Mt_Count.h" + +Mt_Count::Mt_Count() +{ +} + +Mt_Count::~Mt_Count() +{ +} + +void Mt_Count::InitState(int state) +{ + printf("\nDis_Scan_Page %d",state); + display->DisplayState(DisType::Dis_Scan_Page,state,ClearScreen::BOT); +} + +IState *Mt_Count::OnState(StateInfo mode) +{ + return nullptr; +} + + +void Mt_Count::SetBtnCall(std::function call) +{ + +} \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/Mt_Count.h b/device/gxx-linux/motorcontroller/Mt_Count.h new file mode 100644 index 0000000..2ae3036 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Count.h @@ -0,0 +1,12 @@ +#pragma once +#include "IState.h" + +class Mt_Count : public IState +{ +public: + Mt_Count(/* args */); + virtual ~Mt_Count(); + virtual void InitState(int state=0) override; + virtual IState* OnState(StateInfo mode) override; + virtual void SetBtnCall(std::function call) override; +}; diff --git a/device/gxx-linux/motorcontroller/Mt_Error.cpp b/device/gxx-linux/motorcontroller/Mt_Error.cpp new file mode 100644 index 0000000..24bf43a --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Error.cpp @@ -0,0 +1,42 @@ +#include "Mt_Error.h" + +Mt_Error::Mt_Error() +{ + +} + +Mt_Error::~Mt_Error() +{ + +} + +void Mt_Error::InitState(int state) +{ + if(state == (int)HGScannerStatus::Mode_Error_Jam) + display->DisplayState(DisType::Dis_Err_JamIn,0,ClearScreen::All); + if(state == (int)HGScannerStatus::Mode_Error_DoublePaper) + display->DisplayState(DisType::Dis_Err_DoubleFeed,0,ClearScreen::All); + if(state == (int)HGScannerStatus::Mode_Error_Screw) + display->DisplayState(DisType::Dis_Err_PaperScrew,0,ClearScreen::All); + if(state == (int)HGScannerStatus::Mode_Error_Stable) + display->DisplayState(DisType::Dis_Err_Stable,0,ClearScreen::All); + if(state == (int)HGScannerStatus::Mode_Error_AquireTimeout) + display->DisplayState(DisType::Dis_Err_AqrImgTimeout,0,ClearScreen::All); + if(state == (int)HGScannerStatus::Mode_Error_CoverOpen) + display->DisplayState(DisType::Dis_Err_CoverOpen,0,ClearScreen::All); + if(state == (int)HGScannerStatus::Mode_Error_FeedError) + display->DisplayState(DisType::Dis_Err_FeedError,0,ClearScreen::All); + if(state == (int)HGScannerStatus::Mode_Error_NoFeed) + display->DisplayState(DisType::Dis_Err_NoPaper,0,ClearScreen::All); +} + +IState* Mt_Error::OnState(StateInfo mode) +{ + return nullptr; +} + + +void Mt_Error::SetBtnCall(std::function call) +{ + +} \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/Mt_Error.h b/device/gxx-linux/motorcontroller/Mt_Error.h new file mode 100644 index 0000000..e895dc1 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Error.h @@ -0,0 +1,12 @@ +#pragma once +#include "IState.h" + +class Mt_Error : public IState +{ +public: + Mt_Error(/* args */); + virtual ~Mt_Error(); + virtual void InitState(int state=0) override; + virtual IState* OnState(StateInfo mode) override; + virtual void SetBtnCall(std::function call) override; +}; \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/Mt_Idel.cpp b/device/gxx-linux/motorcontroller/Mt_Idel.cpp new file mode 100644 index 0000000..47b4165 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Idel.cpp @@ -0,0 +1,41 @@ +#include "Mt_Idel.h" +#include "Mt_Scan.h" +#include "Mt_Set.h" +#include "Mt_Count.h" +#include "Mt_Error.h" +#include "StateManager.h" + +Mt_Idel::Mt_Idel() +{ + +} + +Mt_Idel::~Mt_Idel() +{ + +} + +void Mt_Idel::InitState(int state) +{ + // display->DisplayState(DisType::Dis_Welcome,0); + // std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + display->DisplayState(DisType::Dis_Idel,0,ClearScreen::All); +} + +IState* Mt_Idel::OnState(StateInfo mode) +{ + if(mode.status == HGScannerStatus::Mode_Scan_Start) + return StateManager::GetState(); + if(mode.status == HGScannerStatus::Mode_Count) + return StateManager::GetState(); + if(mode.status == HGScannerStatus::Mode_Set_Key_Manual) + return StateManager::GetState(); + if(mode.status >= HGScannerStatus::Mode_Error_Jam && mode.status <= HGScannerStatus::Mode_Error_DogEar) + return StateManager::GetState(); + return this; +} + +void Mt_Idel::SetBtnCall(std::function call) +{ + +} \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/Mt_Idel.h b/device/gxx-linux/motorcontroller/Mt_Idel.h new file mode 100644 index 0000000..dbb4106 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Idel.h @@ -0,0 +1,14 @@ +#pragma once +#include "IState.h" + +class Mt_Idel: public IState +{ +private: + /* data */ +public: + Mt_Idel(/* args */); + virtual ~Mt_Idel(); + virtual void InitState(int state=0) override; + virtual IState* OnState(StateInfo mode) override; + virtual void SetBtnCall(std::function call) override; +}; diff --git a/device/gxx-linux/motorcontroller/Mt_Scan.cpp b/device/gxx-linux/motorcontroller/Mt_Scan.cpp new file mode 100644 index 0000000..a39d1b6 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Scan.cpp @@ -0,0 +1,27 @@ +#include "Mt_Scan.h" + +Mt_Scan::Mt_Scan() +{ + +} + +Mt_Scan::~Mt_Scan() +{ + +} + +void Mt_Scan::InitState(int state) +{ + display->DisplayState(DisType::Dis_Scan,0,ClearScreen::All); +} + +IState* Mt_Scan::OnState(StateInfo mode) +{ + return nullptr; +} + + +void Mt_Scan::SetBtnCall(std::function call) +{ + +} \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/Mt_Scan.h b/device/gxx-linux/motorcontroller/Mt_Scan.h new file mode 100644 index 0000000..1b42165 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Scan.h @@ -0,0 +1,12 @@ +#pragma once +#include "IState.h" + +class Mt_Scan: public IState +{ +public: + Mt_Scan(/* args */); + virtual ~Mt_Scan(); + virtual void InitState(int state=0) override; + virtual IState* OnState(StateInfo mode) override; + virtual void SetBtnCall(std::function call) override; +}; \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/Mt_Set.cpp b/device/gxx-linux/motorcontroller/Mt_Set.cpp new file mode 100644 index 0000000..be5c6d8 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Set.cpp @@ -0,0 +1,42 @@ +#include "Mt_Set.h" +#include "Mt_Idel.h" +#include "Mt_Scan.h" +#include "Mt_Set.h" +#include "Mt_Count.h" +#include "StateManager.h" +#include "MenuComponent.h" + +Mt_Set::Mt_Set() +{ + if(!m_menu.get()) + m_menu.reset(new MenuComponent()); +} + +Mt_Set::~Mt_Set() +{ +} + +void Mt_Set::InitState(int state) +{ + m_menu->initmenu(); + display->DisplayState(DisType::Dis_Set_ClearPaperPass, 0,ClearScreen::All); +} + +IState *Mt_Set::OnState(StateInfo mode) +{ + if (mode.status >= HGScannerStatus::Mode_Set_Key_ClearCount && + mode.status <= HGScannerStatus::Mode_Set_Key_Enter) + { + + return this; + } + else{ + + } + +} + +void Mt_Set::SetBtnCall(std::function call) +{ + m_call = call; +} \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/Mt_Set.h b/device/gxx-linux/motorcontroller/Mt_Set.h new file mode 100644 index 0000000..63f0572 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Set.h @@ -0,0 +1,20 @@ +#pragma once +#include "IState.h" + +class MenuComponent; + +class Mt_Set : public IState +{ +private: + /* data */ +public: + Mt_Set(/* args */); + virtual ~Mt_Set(); + virtual void InitState(int state=0) override; + virtual IState* OnState(StateInfo mode) override; + virtual void SetBtnCall(std::function call) override; +private: + std::function m_call; + std::shared_ptr m_menu; +}; + diff --git a/device/gxx-linux/motorcontroller/Mt_Welcome.cpp b/device/gxx-linux/motorcontroller/Mt_Welcome.cpp new file mode 100644 index 0000000..5b881c7 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Welcome.cpp @@ -0,0 +1,27 @@ +#include "Mt_Welcome.h" +#include "StateManager.h" +#include "Mt_Idel.h" + +Mt_Welcome::Mt_Welcome() +{ +} + +Mt_Welcome::~Mt_Welcome() +{ +} + +void Mt_Welcome::InitState(int state) +{ + display->DisplayState(DisType::Dis_Welcome,0,ClearScreen::All); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + display->DisplayState(DisType::Dis_Init,0,ClearScreen::All); +} + +IState *Mt_Welcome::OnState(StateInfo mode) +{ + return StateManager::GetState(); +} + +void Mt_Welcome::SetBtnCall(std::function call) +{ +} \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/Mt_Welcome.h b/device/gxx-linux/motorcontroller/Mt_Welcome.h new file mode 100644 index 0000000..adbda28 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Mt_Welcome.h @@ -0,0 +1,14 @@ +#pragma once +#include "IState.h" + +class Mt_Welcome:public IState +{ +private: + /* data */ +public: + Mt_Welcome(/* args */); + ~Mt_Welcome(); + virtual void InitState(int state=0) override; + virtual IState* OnState(StateInfo mode) override; + virtual void SetBtnCall(std::function call) override; +}; diff --git a/device/gxx-linux/motorcontroller/Selectable.h b/device/gxx-linux/motorcontroller/Selectable.h new file mode 100644 index 0000000..2a55c2e --- /dev/null +++ b/device/gxx-linux/motorcontroller/Selectable.h @@ -0,0 +1,54 @@ +#pragma once +#include +#include +#include +#include +#include +#include "Displaydef.h" + +using namespace std; + +class Selectable +{ +public: + enum class SettingType + { + Set_ClearPass = 1, + Set_Sleep, + Set_FeedStrength, + Set_Poweroff, + Set_ClearCount, + Set_CountMode, + Set_DoubleEn + }; + + enum class SleepTime + { + Sleep_15min = 1, + Sleep_30min, + Sleep_60min, + Sleep_120min, + Sleep_never + }; + + enum class MtStrength + { + Strength_Low = 1, + Strength_Mid, + Strength_High + }; + + + + Selectable() {} + virtual ~Selectable() {} + virtual string get_name() = 0; + virtual int select() = 0; + void setconfirmcall(std::function confirmcall) + { + g_call = confirmcall; + } + +protected: + std::function g_call; +}; diff --git a/device/gxx-linux/motorcontroller/StateControl.cpp b/device/gxx-linux/motorcontroller/StateControl.cpp new file mode 100644 index 0000000..9b4225c --- /dev/null +++ b/device/gxx-linux/motorcontroller/StateControl.cpp @@ -0,0 +1,404 @@ +#include "MenuComponent.h" +#include "DisplayCenter.h" +#include "keymonitor.h" +#include "regsaccess.h" +#include "StateControl.h" +#include "wakeup.hpp" +#include "MotorboardParam.h" + +StateControl::StateControl(std::shared_ptr m_regsAccess,std::shared_ptr wake):m_regs(m_regsAccess),m_wake(wake), +is_runing(false),is_cover_open(false),is_autopaper(false),en_autopaper_key(false){ + m_menu.reset(new MenuComponent()); + m_menu->initmenu(); + m_discenter.reset(new DisplayCenter()); + uint reg6value = 0; + m_regs->read(0x6,reg6value); + auto reg = *(reg6*)®6value; + MotorboardParam::MBParam mb_param = MotorboardParam().GetParam(); + reg.param.work_mode = 0; + reg.param.lift_init_set = mb_param.trayposition; + switch (mb_param.feedmode) + { + case 0: + reg.param.func_feed_low =1; + reg.param.func_feed_high = reg.param.func_feed_mid = 0; + break; + case 1: + reg.param.func_feed_mid =1; + reg.param.func_feed_high = reg.param.func_feed_low = 0; + break; + case 2: + reg.param.func_feed_high =1; + reg.param.func_feed_mid = reg.param.func_feed_low = 0; + break; + default: + reg.param.func_feed_mid =1; + reg.param.func_feed_high = reg.param.func_feed_low = 0; + break; + } + m_regs->write(0x6,reg.value); + auto keycall = [&](int keyvalye) + { + if(wake.get()) + wake->resettime(); + std::cout << "keycallback keyvalue= " << keyvalye << std::endl; + uint value = 0; + auto key = (KeyMonitor::HGKey)(keyvalye); + if((is_autopaper && (!en_autopaper_key)) || (is_autopaper && en_autopaper_key && (key!=KeyMonitor::HGKey::Key_Cancle))) + return ; + if((is_runing && key!=KeyMonitor::HGKey::Key_Cancle)||is_cover_open) + return ; + value = 0; + switch (key) + { + case KeyMonitor::HGKey::Key_Enter: + { + m_regs->read(0x6,value); + auto reg = *(reg6*)&value; + printf("\n reg.param.work_mode = %d ",reg.param.work_mode); + if(reg.param.work_mode !=1) + break; + m_regs->read(0x02,value); + if(!(value&0x10000)) + { + PutMsg(DisType::Dis_Err_NoPaper,0,ClearScreen::All); + break; + } + setrunstate(true); + reg.param.func_encount = 1; + m_regs->write(0x6,reg.value); + reg.param.func_encount = 0; + m_regs->write(0x6,reg.value); + if(m_wake.get()) + m_wake->setsleepfalg(true); + printf("\n m_menu->getcurindex() %d",m_menu->getcurindex()); + m_discenter->PutMsg(DisType::Dis_Set_Count,0,ClearScreen::All); + PutMsg(DisType::Dis_Scan_Page,getpapercount(),ClearScreen::BOT); + break; + } + case KeyMonitor::HGKey::Key_Cancle: + { + m_regs->read(0x06,value); + reg6 func = *(reg6*)&value; + m_menu->setcurindex(0); + m_discenter->PutMsg(func.param.work_mode == 0? (is_runing?DisType::Dis_Scan : DisType::Dis_Idel):(func.param.work_mode == 1?DisType::Dis_Set_Count:DisType::Dis_HandMode),0,ClearScreen::All); + if(m_discenter->getcurdistype() == DisType::Dis_Scan || m_discenter->getcurdistype() == DisType::Dis_Set_Count) + { + PutMsg(DisType::Dis_Scan_Page,getpapercount(),ClearScreen::BOT); + } + autopaperstop?autopaperstop():void(); + if(!is_runing) + break; + func.param.key_stop_enable = true; + m_regs->write(0x06,func.value); + func.param.key_stop_enable = false; + m_regs->write(0x06,func.value); + if(m_wake.get()) + m_wake->setsleepfalg(false); + //is_runing = false; + // if(int(m_discenter->getcurdistype()) > 4 && int(m_discenter->getcurdistype())<14) + // m_discenter->PutMsg(DisType::Dis_Idel,0,ClearScreen::All); + break; + } + case KeyMonitor::HGKey::Key_Count: + { + if(m_discenter->getcurdistype() != DisType::Dis_Idel) + { + m_menu->setcurindex(0); + m_discenter->PutMsg(DisType::Dis_Idel, 0,ClearScreen::All); + } + m_regs->read(0x6,value); + auto reg = *(reg6*)&value; + printf("\n reg.param.work_mode = %d ",reg.param.work_mode); + if(reg.param.work_mode!= 0 && reg.param.work_mode !=1) + break; + if(reg.param.work_mode == 1){ + reg.param.work_mode = 0; + m_keymonitor->setled(KeyMonitor::HGLed::Led_Count_close); + } + else{ + reg.param.work_mode = 1; + clearcount(); + getpapercount(); + PutMsg(DisType::Dis_Scan_Page,getpapercount(),ClearScreen::BOT); + m_keymonitor->setled(KeyMonitor::HGLed::Led_Count_open); + } + m_regs->write(0x6,reg.value); + m_discenter->PutMsg(reg.param.work_mode == 1?DisType::Dis_Set_Count:DisType::Dis_Idel,0, reg.param.work_mode == 1?ClearScreen::TOP : ClearScreen::All); + break; + } + // case KeyMonitor::HGKey::Key_Handle: + // { + // m_regs->read(0x6,value); + // auto reg = *(reg6*)&value; + // printf("\n reg.param.work_mode = %d ",reg.param.work_mode); + // if(reg.param.work_mode!= 0 && reg.param.work_mode !=5) + // break; + // if(reg.param.work_mode == 5){ + // reg.param.work_mode = 0; + // m_keymonitor->setled(KeyMonitor::HGLed::Led_Handle_close); + // } + // else{ + // reg.param.work_mode = 5; + // m_keymonitor->setled(KeyMonitor::HGLed::Led_Handle_open); + // } + // m_regs->write(0x6,reg.value); + // m_discenter->PutMsg(reg.param.work_mode == 5?DisType::Dis_HandMode:DisType::Dis_Idel,0,ClearScreen::All); + // break; + // } + case KeyMonitor::HGKey::Key_DoubleFeed: + { + m_regs->read(0x6,value); + auto reg = *(reg6*)&value; + printf("\n reg.param.key_endouble_feed =%d ",reg.param.key_endouble_feed); + if(reg.param.key_endouble_feed){ + reg.param.key_endouble_feed = 0; + m_keymonitor->setled(KeyMonitor::HGLed::Led_DoubleFeed_close); + } + else{ + reg.param.key_endouble_feed = 1; + m_keymonitor->setled(KeyMonitor::HGLed::Led_DoubleFeed_open); + } + m_regs->write(0x6,reg.value); + break; + } + case KeyMonitor::HGKey::Key_Left: + case KeyMonitor::HGKey::Key_Menu: + case KeyMonitor::HGKey::Key_Right: + { + m_regs->read(0x6,value); + auto reg = *(reg6*)&value; + if(reg.param.work_mode != 0) + break; + if(keyvalye == (int)KeyMonitor::HGKey::Key_Menu) + menu_func(m_menu->getcurtype()); + printf("\n m_menu->getcurindex() %d",m_menu->getcurindex()); + printf("\n mb 6 value%d",reg.value); + if(keyvalye == (int)KeyMonitor::HGKey::Key_Menu && m_menu->getcurindex() == 2) //2 分纸强度项 + m_menu->setcurindex(reg.param.func_feed_high?7:(reg.param.func_feed_mid?8:9)); //7 分纸强度高 8 分纸强度中 9 分纸强度弱 + else if(keyvalye == (int)KeyMonitor::HGKey::Key_Menu && m_menu->getcurindex() == 4) //2 分纸强度项 + m_menu->setcurindex(reg.param.lift_init_set == 2?20:(reg.param.lift_init_set == 1?21:22)); //7 分纸强度高 8 分纸强度中 9 分纸强度弱 + else + m_menu->option(keyvalye); + if(m_menu->getcurindex() >=7 && m_menu->getcurindex()<= 23) + m_discenter->PutMsg(m_menu->getcurtype(),0,ClearScreen::BOT); + else + m_discenter->PutMsg(m_menu->getcurtype(),0,ClearScreen::All); + break; + } + case KeyMonitor::HGKey::Key_Clear: + { + clearcount(); + if(m_discenter->getcurdistype() == DisType::Dis_Count_Page || m_discenter->getcurdistype() == DisType::Dis_Scan_Page) + m_discenter->PutMsg(DisType::Dis_Count_Page,0,ClearScreen::BOT); + break; + } + default: + break; + } + value = 0; + m_regs->read(0x6, value); + m_regs->write(0x6, value | 128); + m_regs->write(0x6, value & 0xffffff7f); + }; + m_keymonitor.reset(new KeyMonitor(keycall)); +} + +StateControl::~StateControl() +{ + uint value; + m_regs->read(0x06,value); + reg6 func = *(reg6*)&value; + func.param.key_stop_enable = true; + m_regs->write(0x06,func.value); + func.param.key_stop_enable = false; + m_regs->write(0x06,func.value); + if(m_menu.get()) + m_menu.reset(); + if(m_discenter.get()) + m_discenter.reset(); + if(m_keymonitor.get()) + m_keymonitor.reset(); +} + +void StateControl::PutMsg(DisType type,int value,ClearScreen clearscreen) +{ + if(m_discenter) + { + if(type == DisType::Dis_Idel) + { + uint value = 0; + m_regs->read(0x6,value); + auto tmp = *(reg6*)&value; + switch (tmp.param.work_mode) + { + case 1: + m_discenter->PutMsg(DisType::Dis_Set_Count,0,ClearScreen::All); + m_discenter->PutMsg(DisType::Dis_Scan_Page,getpapercount(),ClearScreen::BOT); + return ; + case 5: + m_discenter->PutMsg(DisType::Dis_HandMode,0,ClearScreen::All); + return; + default: + m_discenter->PutMsg(type,value,clearscreen); + break; + } + } + else + m_discenter->PutMsg(type,value,clearscreen); + } +} + +void StateControl::menu_func(DisType type) +{ + uint value = 0; + MotorboardParam func_feed; + m_regs->read(0x6,value); + auto tmp = *(reg6*)&value; + switch (type) + { + case DisType::Dis_Set_Poweroff: + system("poweroff"); + break; + case DisType::Dis_Set_ClearPaperPass: + tmp.param.func_clean_passthro = 1; + m_regs->write(0x6,tmp.value); + tmp.param.func_clean_passthro = 0; + m_regs->write(0x6,tmp.value); + break; + case DisType::Dis_Set_PollPI_High: + tmp.param.func_feed_high = 1; + tmp.param.func_feed_low = tmp.param.func_feed_mid = 0; + m_regs->write(0x6,tmp.value); + func_feed.GetOrSetFeedMode(false,2); + break; + case DisType::Dis_Set_PollPI_Mid: + tmp.param.func_feed_mid = 1; + tmp.param.func_feed_low = tmp.param.func_feed_high = 0; + m_regs->write(0x6,tmp.value); + func_feed.GetOrSetFeedMode(false,1); + break; + case DisType::Dis_Set_PollPI_Low: + tmp.param.func_feed_low = 1; + tmp.param.func_feed_mid = tmp.param.func_feed_high = 0; + m_regs->write(0x6,tmp.value); + func_feed.GetOrSetFeedMode(false,0); + break; + case DisType::Dis_Set_SleepMode_5M: + if(m_wake.get()) + m_wake->settime(300); + break; + case DisType::Dis_Set_SleepMode_10M: + if(m_wake.get()) + m_wake->settime(600); + break; + case DisType::Dis_Set_SleepMode_20M: + if(m_wake.get()) + m_wake->settime(1200); + break; + case DisType::Dis_Set_SleepMode_30M: + if(m_wake.get()) + m_wake->settime(1800); + break; + case DisType::Dis_Set_SleepMode_1H: + if(m_wake.get()) + m_wake->settime(3600); + break; + case DisType::Dis_Set_SleepMode_2H: + if(m_wake.get()) + m_wake->settime(7200); + break; + case DisType::Dis_Set_SleepMode_4H: + if(m_wake.get()) + m_wake->settime(14400); + break; + case DisType::Dis_Set_SleepMode_NEVER: + if(m_wake.get()) + m_wake->settime(-1); + break; + case DisType::Dis_Set_TrayPosition_High: + tmp.param.lift_init_set = 2; + m_regs->write(0x6,tmp.value); + func_feed.GetOrSetTrayPosition(false,2); + break; + case DisType::Dis_Set_TrayPosition_Mid: + tmp.param.lift_init_set = 1; + m_regs->write(0x6,tmp.value); + func_feed.GetOrSetTrayPosition(false,1); + break; + case DisType::Dis_Set_TrayPosition_Low: + tmp.param.lift_init_set = 0; + m_regs->write(0x6,tmp.value); + func_feed.GetOrSetTrayPosition(false,0); + break; + default: + break; + } +} + +void StateControl::lcdcontrol(int led){ + if(m_keymonitor) + m_keymonitor->setled((KeyMonitor::HGLed)led); +} + +void StateControl::setrunstate(bool value) +{ + is_runing = value; + if(is_runing){ + m_keymonitor->setled(KeyMonitor::HGLed::Led_Enter_open); + m_menu->setcurindex(0); + } + else + { + uint value = 0; + m_regs->read(0x6,value); + auto tmp = *(reg6*)&value; + m_keymonitor->setled(tmp.param.key_endouble_feed?KeyMonitor::HGLed::Led_DoubleFeed_open : KeyMonitor::HGLed::Led_DoubleFeed_close); + m_keymonitor->setled(KeyMonitor::HGLed::Led_Enter_close); + } +} + +bool StateControl::getrunstate() +{ + return is_runing; +} + +void StateControl::setcoverstate(bool value) +{ + is_cover_open = value; +} +bool StateControl::getcoverstate() +{ + return is_cover_open; +} +void StateControl::setmenuindex(int menu){ + m_menu->setcurindex(menu); +} + +uint StateControl::getpapercount(){ + unsigned int papercount = 0; + m_regs->read(0x02,papercount); + printf("\nmotorcount = %d ",papercount&0x3fff); + return papercount&0x3fff; +} + +void StateControl::clearcount(){ + uint value = 0; + m_regs->read(0x6,value); + auto reg = *(reg6*)&value; + reg.param.func_clear_count = 1; + m_regs->write(0x6,reg.value); + reg.param.func_clear_count = 0; + m_regs->write(0x6,reg.value); +} + +void StateControl::setautopaperflag(bool enable,bool enkey){ + is_autopaper = enable; + en_autopaper_key = enkey; +} + + void StateControl::setautopaperstopcallback(std::function func) + { + if(func) + autopaperstop = func; + } \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/StateControl.h b/device/gxx-linux/motorcontroller/StateControl.h new file mode 100644 index 0000000..eb95d1e --- /dev/null +++ b/device/gxx-linux/motorcontroller/StateControl.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include +class MenuComponent; +class DisplayCenter; +class KeyMonitor; +class IRegsAccess; +class WakeUp; +enum class DisType; +enum class ClearScreen; + +class StateControl{ +typedef union reg6 +{ + struct{ + unsigned int work_mode : 3; + unsigned int func_clean_passthro : 1; + unsigned int func_feed_low : 1; + unsigned int func_feed_mid : 1; + unsigned int func_feed_high : 1; + unsigned int key_sound : 1; + unsigned int key_endouble_feed : 1; + unsigned int func_encount : 1; + unsigned int func_clear_count : 1; + unsigned int motor_choose : 2; + unsigned int wr_en : 1; + unsigned int motor_addr : 8; + unsigned int key_stop_enable : 1; + unsigned int lift_init_set: 2; + }param; + unsigned int value; +} REG6; + +public: + StateControl(std::shared_ptr m_regsAccess,std::shared_ptr wake); + ~StateControl(); + void PutMsg(DisType type,int value,ClearScreen clearscreen); + void setrunstate(bool value); + bool getrunstate(); + void setcoverstate(bool value); + bool getcoverstate(); + void setmenuindex(int menu); + void lcdcontrol(int led); + void setautopaperflag(bool enable,bool enkey); + void setautopaperstopcallback(std::function func); + +private: + void menu_func(DisType type); + uint getpapercount(); + void clearcount(); + std::shared_ptr m_menu; + std::shared_ptr m_discenter; + std::shared_ptr m_keymonitor; + std::shared_ptr m_regs; + std::shared_ptr m_wake; + std::function autopaperstop; + volatile bool is_runing; + volatile bool is_cover_open; + volatile bool is_autopaper; + volatile bool en_autopaper_key; +}; \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/StateManager.cpp b/device/gxx-linux/motorcontroller/StateManager.cpp new file mode 100644 index 0000000..9ee61c9 --- /dev/null +++ b/device/gxx-linux/motorcontroller/StateManager.cpp @@ -0,0 +1,4 @@ +#include "StateManager.h" + + +std::map> StatePreManager::motorState; \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/StateManager.h b/device/gxx-linux/motorcontroller/StateManager.h new file mode 100644 index 0000000..aa97a32 --- /dev/null +++ b/device/gxx-linux/motorcontroller/StateManager.h @@ -0,0 +1,30 @@ +#pragma once +#include "IState.h" +#include +#include + +class StatePreManager +{ +protected: + static std::map> motorState; +}; + + +template +class StateManager:public StatePreManager +{ +public: + StateManager(/* args */) = delete; + StateManager(const StateManager&) = delete; + StateManager& operator=(const StateManager&) = delete; + static IState* GetState(int state=0) + { + std::string type_name = typeid(T).name(); + std::map>::iterator iter = motorState.find(type_name); + if (iter == motorState.end()) { + motorState.insert(std::pair>(type_name, std::shared_ptr(new T))); + } + motorState[type_name]->InitState(state); + return motorState[type_name].get(); + } +}; diff --git a/device/gxx-linux/motorcontroller/Statedef.h b/device/gxx-linux/motorcontroller/Statedef.h new file mode 100644 index 0000000..8a62c1e --- /dev/null +++ b/device/gxx-linux/motorcontroller/Statedef.h @@ -0,0 +1,38 @@ +#pragma once + + enum class HGScannerStatus + { + Mode_Welcome, + Mode_Idel, + Mode_Count, + Mode_Scan_Start, + Mode_Scanning, + Mode_Error_Jam, + Mode_Error_DoublePaper, + Mode_Error_Screw, + Mode_Error_Stable, + Mode_Error_AquireTimeout, + Mode_Error_AquireFailed, + Mode_Error_NoFeed, + Mode_Error_CoverOpen, + Mode_Flatting, + Mode_Error_Size, + Mode_Error_DogEar, + Mode_Set_Key_ClearCount, + Mode_Set_Key_Left, + Mode_Set_Key_Manual, + Mode_Set_Key_Right, + Mode_Set_Key_Count, + Mode_Set_HandMode, + Mode_Set_Key_EnDoubleFeed, + Mode_Set_Key_Back, + Mode_Set_Key_Enter, //如需增加状态显示 在之后添加 请勿在此之前添加 避免影响其他代码 + Mode_Error_FeedError + }; + + struct StateInfo + { + HGScannerStatus status; + unsigned int value; + }; + \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/Subject.h b/device/gxx-linux/motorcontroller/Subject.h new file mode 100644 index 0000000..624dbd9 --- /dev/null +++ b/device/gxx-linux/motorcontroller/Subject.h @@ -0,0 +1,17 @@ +#pragma once +#include +#include +#include +#include +#include "Observer.h" + +using namespace std; + +class Subject +{ +public: + virtual ~Subject(){} + virtual void notify() = 0; + virtual void attach(Observer* this_observer) = 0; + virtual void dettach(Observer* this_observer) = 0; +}; \ No newline at end of file diff --git a/device/gxx-linux/motorcontroller/xmake.lua b/device/gxx-linux/motorcontroller/xmake.lua new file mode 100644 index 0000000..3931dbd --- /dev/null +++ b/device/gxx-linux/motorcontroller/xmake.lua @@ -0,0 +1,10 @@ +add_rules("mode.debug", "mode.release") + +target("motorcontroller") + set_kind("static") + add_files("*.cpp") + add_includedirs(".", { public = true}) + add_deps("regs","capimage","deviceio","display","applog","keymonitor") + add_includedirs("../scanner",{public = true}) + --add_includedirs("../capimage",{public = true}) + add_packages("common") \ No newline at end of file diff --git a/device/gxx-linux/out.text b/device/gxx-linux/out.text new file mode 100644 index 0000000..9a32dd3 --- /dev/null +++ b/device/gxx-linux/out.text @@ -0,0 +1 @@ +测试次数 = 1 异常次数 = 1 \ No newline at end of file diff --git a/device/gxx-linux/packages/common.pkg/include/StopWatch.h b/device/gxx-linux/packages/common.pkg/include/StopWatch.h index afa4ee9..bb8aede 100644 --- a/device/gxx-linux/packages/common.pkg/include/StopWatch.h +++ b/device/gxx-linux/packages/common.pkg/include/StopWatch.h @@ -1,5 +1,52 @@ #pragma once #include +#include + +static std::string GetCurrentTimeStamp(int time_stamp_type ) +{ + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + + std::time_t now_time_t = std::chrono::system_clock::to_time_t(now); + std::tm* now_tm = std::localtime(&now_time_t); + + char buffer[128]; + strftime(buffer, sizeof(buffer), "%F %T", now_tm); + + std::ostringstream ss; + ss.fill('0'); + + std::chrono::milliseconds ms; + std::chrono::microseconds cs; + std::chrono::nanoseconds ns; + + switch (time_stamp_type) + { + case 0: + ss << buffer; + break; + case 1: + ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; + ss << buffer << ":" << ms.count(); + break; + case 2: + ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; + cs = std::chrono::duration_cast(now.time_since_epoch()) % 1000000; + ss << buffer << ":" << ms.count() << ":" << cs.count() % 1000; + break; + case 3: + ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; + cs = std::chrono::duration_cast(now.time_since_epoch()) % 1000000; + ns = std::chrono::duration_cast(now.time_since_epoch()) % 1000000000; + ss << buffer << ":" << ms.count() << ":" << cs.count() % 1000 << ":" << ns.count() % 1000; + break; + default: + ss << buffer; + break; + } + + return ss.str(); +} + class StopWatch { diff --git a/device/gxx-linux/packages/common.pkg/include/commondef.h b/device/gxx-linux/packages/common.pkg/include/commondef.h index 386b2ea..671b0b5 100644 --- a/device/gxx-linux/packages/common.pkg/include/commondef.h +++ b/device/gxx-linux/packages/common.pkg/include/commondef.h @@ -1,30 +1,20 @@ #pragma once #include #include -#include +#include + #define FWVersionEN -#define G400 +#define G100 #ifdef G200 -#define FWVersion "G2393A1215" +#define FWVersion "G2393C0322" #define SERIALNUM "G2396021071101" -#elif defined G300 -#define FWVersion "G3393C0303" -#define SERIALNUM "G3396021071101" -#elif defined G400 -#define FWVersion "G4393C0303" -#define SERIALNUM "G4396021071101" #else -#define FWVersion "G1393A1215" +#define FWVersion "G1393C0322" #define SERIALNUM "G1396021071101" #endif -#ifdef TEST_MODE -#define HG_SAVEIMG cv::imwrite -#else -#define HG_SAVEIMG -#endif //#ifdef FWVersionEN //#pragma warnning("WARNNING! current fareware version is :" FWVersion) //#endif @@ -116,13 +106,15 @@ struct MotorBoardGlue const std::function os_mode_call, const std::function set_sleepmode_call, const std::function mltop_call, - std::function auto_paper) + std::function auto_paper, + const std::function coveropen) : m_error_call(error_call), m_scan_done_call(scan_done_call), m_os_mode_call(os_mode_call), m_set_sleepmode_call(set_sleepmode_call), m_mltop_call(mltop_call), - m_auto_paper(auto_paper) + m_auto_paper(auto_paper), + m_coveropen_call(coveropen) { } @@ -132,11 +124,13 @@ struct MotorBoardGlue std::function m_set_sleepmode_call; std::function m_mltop_call; std::function m_auto_paper; + std::function m_coveropen_call; }; + struct ScannerNativeParam { - u32 TotalScanned; //扫描总计数 + u32 TotalScanned; //扫描总计�? u32 RollerNum; //滚轴计数 u32 H_ratio; //横向修正系数 u32 V_ratio; //纵向修正系数 @@ -144,16 +138,19 @@ struct ScannerNativeParam u32 FeedErrorTimes; //搓纸失败次数 u32 DoubleFeedTimes; //双张次数 u32 ScanSessionsCount; //总计扫描次数 - u16 gray_sp; //灰度sp值 - u16 color_sp; //彩色sp值 - int sleeptime; //休眠模式时间 -1 不休眠 - std::string SerialNum; //序列号 - std::string Token; //识别码 - u32 clr_maxbright; //彩色平场校正最大亮度 - u32 gray_maxbright; //灰度平场校正最大亮度 + u16 gray_sp; //灰度sp�? + u16 color_sp; //彩色sp�? + int sleeptime; //休眠模式时间 -1 不休�? + std::string SerialNum; //序列�? + std::string Token; //识别�? + u32 clr_maxbright; //彩色平场校正最大亮�? + u32 gray_maxbright; //灰度平场校正最大亮�? u32 speedmode; //速度模式 G100 0->70 1->80 2->90 3->100 G200 0->100 1->110 2->120 3->130 u16 Vid; //USB vid u16 Pid; //USB Pid + std::uint32_t chu_motor_speed_200; // G100 G200 出纸电机速度 + std::uint32_t chu_motor_speed_300; // G100 G200 出纸电机速度 + std::uint32_t chu_motor_speed_600; // G100 G200 出纸电机速度 }; enum TwSS : unsigned short @@ -260,7 +257,7 @@ struct HGSize } }; -//usb int 端点 返回消息的生产者 +//usb int 端点 返回消息的生产�? enum HGType { MtBoard = 1, @@ -273,7 +270,7 @@ enum HGType MBEvent, }; -//usb int 端点通信结构体 +//usb int 端点通信结构�? struct HGIntInfo { HGType From; @@ -283,9 +280,6 @@ struct HGIntInfo enum SpeedMode { - PPM40 = 40, - PPM50 = 50, - PPM60 = 60, PPM70 = 70, PPM80 = 80, PPM90 = 90, @@ -317,27 +311,30 @@ typedef struct static std::map cameraparmSp = { #ifdef G100 - {PPM70, {.colorSp_200 = 1341 , .graySp_200= 4030,.colorSp_300 = 1377 ,.graySp_300 = 4133,.colorSp_600 = 1701 ,.graySp_600 = 5105 , 1}}, - {PPM80, {.colorSp_200 = 1202 , .graySp_200= 3609,.colorSp_300 = 1230 ,.graySp_300 = 3691,.colorSp_600 = 1701 ,.graySp_600 = 5105 , 2}}, - {PPM90, {.colorSp_200 = 1024 , .graySp_200= 3072,.colorSp_300 = 1110 ,.graySp_300 = 3330,.colorSp_600 = 1701 ,.graySp_600 = 5105 , 0}}, - {PPM100, {.colorSp_200 = 847 , .graySp_200= 2541,.colorSp_300 = 1011 ,.graySp_300 = 3036,.colorSp_600 = 1701 ,.graySp_600 = 5105 , 3}},//G100 3399 暂无100 ppm - {PPM110, {.colorSp_200 = 847 , .graySp_200= 2541,.colorSp_300 = 1011 ,.graySp_300 = 3036,.colorSp_600 = 1701 ,.graySp_600 = 5105 , 3}}, -#elif defined G200 - {PPM100, {.colorSp_200 = 838 , .graySp_200= 2514,.colorSp_300 = 895 ,.graySp_300 = 2689,.colorSp_600 = 1705 ,.graySp_600 = 5117 , 0}}, - {PPM110, {.colorSp_200 = 838 , .graySp_200= 2514,.colorSp_300 = 895 ,.graySp_300 = 2689,.colorSp_600 = 1705 ,.graySp_600 = 5117 , 1}}, - {PPM120, {.colorSp_200 = 838 , .graySp_200= 2514,.colorSp_300 = 895 ,.graySp_300 = 2689,.colorSp_600 = 1705 ,.graySp_600 = 5117 , 3}}, - {PPM130, {.colorSp_200 = 838 , .graySp_200= 2514,.colorSp_300 = 895 ,.graySp_300 = 2689,.colorSp_600 = 1705 ,.graySp_600 = 5117 , 2}} //默认 140 -#elif defined G300 - {PPM40, {.colorSp_200 = 838 , .graySp_200= 2514,.colorSp_300 = 895 ,.graySp_300 = 2689,.colorSp_600 = 1705 ,.graySp_600 = 5117 , 0}}, - {PPM50, {.colorSp_200 = 838 , .graySp_200= 2514,.colorSp_300 = 895 ,.graySp_300 = 2689,.colorSp_600 = 1705 ,.graySp_600 = 5117 , 1}}, - {PPM60, {.colorSp_200 = 838 , .graySp_200= 2514,.colorSp_300 = 895 ,.graySp_300 = 2689,.colorSp_600 = 1705 ,.graySp_600 = 5117 , 2}}, - {PPM70, {.colorSp_200 = 838 , .graySp_200= 2514,.colorSp_300 = 895 ,.graySp_300 = 2689,.colorSp_600 = 1705 ,.graySp_600 = 5117 , 3}} //默认 140 + {PPM70, {.colorSp_200 = 1150 , .graySp_200= 3450,.colorSp_300 = 1207 ,.graySp_300 = 3621,.colorSp_600 = 1822 ,.graySp_600 = 5466 , 1}}, + {PPM80, {.colorSp_200 = 1150 , .graySp_200= 3450,.colorSp_300 = 1207 ,.graySp_300 = 3621,.colorSp_600 = 1822 ,.graySp_600 = 5466 , 2}}, + {PPM90, {.colorSp_200 = 944 , .graySp_200= 2834,.colorSp_300 = 1019 ,.graySp_300 = 3059,.colorSp_600 = 1822 ,.graySp_600 = 5466 , 0}}, + {PPM100, {.colorSp_200 = 847 , .graySp_200= 2541,.colorSp_300 = 875 ,.graySp_300 = 2626,.colorSp_600 = 1822 ,.graySp_600 = 5466 , 3}},//G100 3399 暂无100 ppm + {PPM110, {.colorSp_200 = 847 , .graySp_200= 2541,.colorSp_300 = 875 ,.graySp_300 = 2626,.colorSp_600 = 1822 ,.graySp_600 = 5466 , 3}}, #else - {PPM40, {.colorSp_200 = 2426 , .graySp_200= 7268,.colorSp_300 = 1615 ,.graySp_300 = 4849,.colorSp_600 = 1567 ,.graySp_600 = 4701 , 0}}, - {PPM50, {.colorSp_200 = 1950 , .graySp_200= 5870,.colorSp_300 = 1303 ,.graySp_300 = 3909,.colorSp_600 = 1567 ,.graySp_600 = 4701 , 1}}, - {PPM60, {.colorSp_200 = 1668 , .graySp_200= 5004,.colorSp_300 = 1080 ,.graySp_300 = 3248,.colorSp_600 = 1567 ,.graySp_600 = 4701 , 2}}, - {PPM70, {.colorSp_200 = 1287 , .graySp_200= 3864,.colorSp_300 = 859 ,.graySp_300 = 2477,.colorSp_600 = 1567 ,.graySp_600 = 4701 , 3}}, - {PPM80, {.colorSp_200 = 1245 , .graySp_200= 3735,.colorSp_300 = 830 ,.graySp_300 = 2490,.colorSp_600 = 1567 ,.graySp_600 = 4701 , 4}} + {PPM100, {.colorSp_200 = 816 , .graySp_200= 2450,.colorSp_300 = 878 ,.graySp_300 = 2637,.colorSp_600 = 1531 ,.graySp_600 = 4595 , 0}}, + {PPM110, {.colorSp_200 = 816 , .graySp_200= 2450,.colorSp_300 = 878 ,.graySp_300 = 2637,.colorSp_600 = 1531 ,.graySp_600 = 4595 , 1}}, + {PPM120, {.colorSp_200 = 816 , .graySp_200= 2450,.colorSp_300 = 878 ,.graySp_300 = 2637,.colorSp_600 = 1531 ,.graySp_600 = 4595 , 3}}, + {PPM130, {.colorSp_200 = 816 , .graySp_200= 2450,.colorSp_300 = 878 ,.graySp_300 = 2637,.colorSp_600 = 1531 ,.graySp_600 = 4595 , 2}} //默认 140 +#endif +}; + +static std::map anlogic_freq = { +#ifdef G100 + {PPM70, 1}, + {PPM80, 2}, + {PPM90, 3}, + {PPM110, 4}, +#else + {PPM100, 1}, + {PPM110, 2}, + {PPM120, 3}, + {PPM130, 4} #endif }; @@ -346,70 +343,39 @@ static std::map scannerSp = { {PPM70, {0x42d, 0xc88 , 1}}, {PPM80, {0x37f, 0xa7f, 2}}, {PPM90, {0x2B6, 0x822, 0}}, - //{PPM100, {0x27C, 0x775, 0}},//G100 3399 暂无100 ppm + {PPM100, {0x27C, 0x775, 0}},//G100 3399 暂无100 ppm {PPM110, {0x24e, 0x706, 3}}, -#elif defined G200 - {PPM100, {0x42d, 0xc88, 0}}, +#else + {PPM100, {0x27C, 0x775, 0}}, {PPM110, {0x27C, 0x775, 1}}, {PPM120, {0x27C, 0x775, 3}}, - {PPM130, {0x27C, 0x775, 2}}, //默认 140 -#elif defined G300 - {PPM40, {0x42d, 0xc88, 0}}, - {PPM50, {0x27C, 0x775, 1}}, - {PPM60, {0x27C, 0x775, 2}}, - {PPM70, {0x27C, 0x775, 3}}, -#else - {PPM40, {0x42d, 0xc88, 0}}, - {PPM50, {0x27C, 0x775, 1}}, - {PPM60, {0x27C, 0x775, 2}}, - {PPM70, {0x27C, 0x775, 3}}, - {PPM80, {0x42d, 0xc88, 4}}, + {PPM130, {0x27C, 0x775, 2}} //默认 140 #endif }; -#ifdef G300 -static std::map papersMap= { - {PaperSize::G400_A3, {1728, 11100}}, - {PaperSize::G400_A4, {1728, 8100}}, - {PaperSize::G400_A4R, {1728, 6000}}, - {PaperSize::G400_A5, {1728, 8100}}, - {PaperSize::G400_A5R, {1728, 8100}}, - {PaperSize::G400_A6, {1728, 8100}}, - {PaperSize::G400_A6R, {1728, 8100}}, - {PaperSize::G400_B4, {1728, 10800}}, - {PaperSize::G400_B5, {1728, 10800}}, - {PaperSize::G400_B5R, {1728, 6600}}, - {PaperSize::G400_B6, {1728, 6600}}, - {PaperSize::G400_B6R, {1728, 6600}}, - {PaperSize::G400_DOUBLELETTER, {1728, 10800}}, - {PaperSize::G400_B6R, {1728, 10800}}, - {PaperSize::G400_LEGAL, {1728, 11100}}, - {PaperSize::G400_LETTER, {1728, 11100}}, - {PaperSize::G400_MAXSIZE, {1728, 16002}}, - }; -#else static std::map papersMap = { - {PaperSize::G400_A3, {1632, 11100}}, - {PaperSize::G400_A4, {1632, 8400}}, - {PaperSize::G400_A4R, {1632, 6000}},//6000 - {PaperSize::G400_A5, {1632, 6600}}, - {PaperSize::G400_A5R, {1632, 4500}}, - {PaperSize::G400_A6, {1632, 4500}}, - {PaperSize::G400_A6R, {1632, 4500}}, - {PaperSize::G400_B4, {1632, 11100}}, - {PaperSize::G400_B5, {1632, 8400}}, - {PaperSize::G400_B5R, {1632, 6600}}, - {PaperSize::G400_B6, {1632, 6600}}, - {PaperSize::G400_DOUBLELETTER, {1632, 11100}}, - {PaperSize::G400_B6R, {1632, 6600}}, - {PaperSize::G400_LEGAL, {1632, 11100}}, - {PaperSize::G400_LETTER, {1632, 8400}}, - {PaperSize::G400_LETTERR, {1632, 11100}}, + {PaperSize::G400_A3, {1632, 10800}}, + {PaperSize::G400_A4, {1632, 8100}}, + {PaperSize::G400_A4R, {1632, 6000}}, + {PaperSize::G400_A5, {1632, 6000}}, + {PaperSize::G400_A5R, {1632, 6000}}, + {PaperSize::G400_A6, {1632, 6000}}, + {PaperSize::G400_A6R, {1632, 6000}}, + {PaperSize::G400_B4, {1632, 10800}}, + {PaperSize::G400_B5, {1632, 8100}}, + {PaperSize::G400_B5R, {1632, 6000}}, + {PaperSize::G400_B6, {1632, 6000}}, + {PaperSize::G400_DOUBLELETTER, {1632, 10800}}, + {PaperSize::G400_B6R, {1632, 6000}}, + {PaperSize::G400_LEGAL, {1632, 10800}}, + {PaperSize::G400_LETTER, {1632, 8100}}, + {PaperSize::G400_LETTERR, {1632, 10800}}, {PaperSize::G400_MAXSIZE, {1632, 16002}}, - {PaperSize::G400_AUTO, {1632, 11100}}, + {PaperSize::G400_AUTO, {1632, 10800}}, {PaperSize::G400_MAXAUTO, {1632, 16002}}, }; -#endif + +// pair unit:mm static std::map paperHeight={ {PaperSize::G400_A3, 475}, {PaperSize::G400_A4, 337}, @@ -427,10 +393,11 @@ static std::map paperHeight={ {PaperSize::G400_LEGAL, 386}, {PaperSize::G400_LETTER, 339}, {PaperSize::G400_LETTERR, 276}, - {PaperSize::G400_MAXSIZE, 1040},//300 dpi max heigth + {PaperSize::G400_MAXSIZE, 1040},//300 dpi max heigth 690 {PaperSize::G400_AUTO, 1040},//300 dpi max heigth {PaperSize::G400_MAXAUTO, 1040}//300 dpi max heigth }; + enum Scanner_Reg_Defs { SR_CMD, @@ -544,6 +511,14 @@ enum Scanner_Reg_Defs SR_SCAN_CNT, }; +typedef union Ctrol_Description{ + std::uint32_t value; + struct{ + std::uint32_t direction : 1; + std::uint32_t unused : 31; + }Param; +}CtrolDescription; + enum Updata_Stautus { Start_updata, @@ -686,6 +661,9 @@ STR(str2) #define S_INFO_SPEEDMODE "SpeedMode" #define S_INFO_VID "VID" #define S_INFO_PID "PID" +#define S_INFO_CHUZHI_MOTOR_SPEED_200 "Chu_Motor_Speed_200" +#define S_INFO_CHUZHI_MOTOR_SPEED_300 "Chu_Motor_Speed_300" +#define S_INFO_CHUZHI_MOTOR_SPEED_600 "Chu_Motor_Speed_600" #pragma pack(push) #pragma pack(4) @@ -763,8 +741,8 @@ typedef struct tagCrop_Rect int enable; int x; /*****自定义裁切区域左上角x坐标*/ int y; /*****自定义裁切区域左上角y坐标*/ - int width; /*****自定义裁切区域宽度*******/ - int height; /*****自定义裁切区域高度*******/ + int width; /*****自定义裁切区域宽�?******/ + int height; /*****自定义裁切区域高�?******/ }CropRect; typedef enum tagMulti_Output { @@ -791,67 +769,67 @@ typedef struct tagHhardware_Params_3399 struct GScanCap { - uint8_t papertype; /**< the current paper source ADF or Flatbed*/ - PaperAlign paperAlign; /**< 纸张放置方向*/ - uint8_t en_sizecheck; /**< 尺寸检测*/ - float imageRotateDegree; /**< 旋转角度*/ - uint8_t is_duplex; /**< True to use duplex false for simplex, ignored if flatbed*/ - uint8_t en_fold; /**< 对折*/ - int pixtype; /**< type of pixels to transfer image as */ - int automaticcolor; /**< 顔色自動識別*/ - int automaticcolortype; /**< 顔色自動識別后非彩色上傳類型*/ + uint8_t papertype; + PaperAlign paperAlign; + uint8_t en_sizecheck; + float imageRotateDegree; + uint8_t is_duplex; + uint8_t en_fold; + int pixtype; + int automaticcolor; + int automaticcolortype; //ScanRect scanrect; - float resolution_dst; /**< horizontal resolution */ - float resolution_native; /**< 实际扫描DPI*/ - float gamma; /**< Gamma */ - float contrast; /**< Contrast */ - float brightness; /**< Brightness */ - float threshold; /**< Threshold */ - uint8_t is_autocontrast; /**< 自动对比度*/ - uint8_t is_autocrop; /**< 自动裁切*/ - uint8_t is_autodiscradblank_normal; /**< 自动丢弃空白页通用*/ - int discardblank_percent; /**< 跳过空白页阀值*/ - uint8_t is_autodiscradblank_vince; /**< 自动丢弃空白页发票*/ - uint8_t is_switchfrontback; /**< 交换正反面*/ - uint8_t autodescrew; /**< 自动纠偏*/ - uint8_t multi_output_red; /**< 多流输出*/ - uint8_t hsvcorrect; /**< 答题卡除红*/ - uint8_t filter; /**< 除色*/ - uint8_t sharpen; /**< 锐化模糊*/ - uint8_t enhance_color; /**< 颜色增强*/ - uint8_t fillbackground; /**< 填黑框*/ - bool is_convex; /**< 填黑框模式,true为凸多边形填充,false为凹多边形填充,默认true*/ - int noise; /**< 除噪像素,能够消除noise宽度的背景竖条纹干扰,默认40*/ - int indent; /**< 轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默认5*/ - int AutoCrop_threshold; /**< 自动裁剪二值化阈值,取值范围(0, 255),默认40*/ - unsigned short scannum; /**< 扫描张数*/ - uint8_t is_backrotate180; /**< 背面旋转180*/ - uint8_t is_dogeardetection; /**< 折角检测*/ - HardwareCaps hardwarecaps; /**< 硬件扫描参数*/ - FillHole fillhole; /**< 穿孔移除>*/ - DetachNoise detachnoise; /**< 黑白降噪*/ - uint8_t is_autotext; /**< 自动文本方向识别 此处大小116字节*/ - bool isfillcolor; /**< 自动裁切颜色填充>*/ - int refuseInflow; /**< 防止渗透>*/ - int colorCorrection; /**< 色彩校正>*/ - int removeMorr; /**< 去除摩尔纹>*/ - int errorExtention; /**< 错误扩散>*/ - int textureRemove; /**< 除网纹>*/ - int splitImage; /**< 图像拆分>*/ - CropRect cropRect; /**< 自定义裁切>*/ - MultiOutput multiOutput; /**< 多流输出>*/ - bool normalCrop; /**< 自动裁切深色样张>*/ - uint32_t dogeardistabce; /**< 折角检测理论顶点到实际轮廓最新距离>*/ - bool fadeback; /**< 除底色>*/ - int fadebackrange; /**< 除底色范围>*/ - bool isuploadexceptionimage; /**< 是否上传双张报错后的异常图像>*/ - int fillholeratio_up; /**< 穿孔移除上下左右范围>*/ - int fillholeratio_down; + float resolution_dst; + float resolution_native; + float gamma; + float contrast; + float brightness; + float threshold; + uint8_t is_autocontrast; + uint8_t is_autocrop; + uint8_t is_autodiscradblank_normal; + int discardblank_percent; + uint8_t is_autodiscradblank_vince; + uint8_t is_switchfrontback; + uint8_t autodescrew; + uint8_t multi_output_red; + uint8_t hsvcorrect; + uint8_t filter; + uint8_t sharpen; + uint8_t enhance_color; + uint8_t fillbackground; + bool is_convex; + int noise; + int indent; + int AutoCrop_threshold; + unsigned short scannum; + uint8_t is_backrotate180; + uint8_t is_dogeardetection; + HardwareCaps hardwarecaps; + FillHole fillhole; + DetachNoise detachnoise; + uint8_t is_autotext; + bool isfillcolor; + int refuseInflow; + int colorCorrection; + int removeMorr; + int errorExtention; + int textureRemove; + int splitImage; + CropRect cropRect; + MultiOutput multiOutput; + bool normalCrop; + uint32_t dogeardistabce; + bool fadeback; + int fadebackrange; + bool isuploadexceptionimage; + int fillholeratio_up; + int fillholeratio_down; int fillholeratio_left; int fillholeratio_right; std::uint8_t fold_concatmode; /*拼接模式*/ int HsvFilterType; /**< 答题卡留红除杂色功能类型 暂定0 为关闭;1为留红除杂色>*/ bool is_colorcast; /**< 色偏校正>*/ - uint32_t reserve[1024]; /**< 预留4096字节做协议扩展*/ + uint32_t reserve[1024]; /**< 预留4096字节做协议扩展*/ }; -#pragma pack(pop) \ No newline at end of file +#pragma pack(pop) diff --git a/device/gxx-linux/packages/common.pkg/xmake.lua b/device/gxx-linux/packages/common.pkg/xmake.lua index 5f559dc..75057fb 100644 --- a/device/gxx-linux/packages/common.pkg/xmake.lua +++ b/device/gxx-linux/packages/common.pkg/xmake.lua @@ -1,5 +1,4 @@ -- 添加一个zlib包自动配置选项 - option("common") -- 设置是否在xmake f -h配置菜单中显示 diff --git a/device/gxx-linux/regs/serialib.cpp b/device/gxx-linux/regs/serialib.cpp index 0cb5aa9..c1d9abf 100644 --- a/device/gxx-linux/regs/serialib.cpp +++ b/device/gxx-linux/regs/serialib.cpp @@ -241,6 +241,7 @@ char serialib::Open(const char *Device,const unsigned int Bauds) options.c_cc[VTIME] = 0; // Timer unused options.c_cc[VMIN] = 0; // At least on character before satisfy reading tcsetattr(fd, TCSANOW, &options); // Activate the settings + tcflush(fd,TCIOFLUSH); return (1); // Success #endif } diff --git a/device/gxx-linux/regs/uartregaccessb.cpp b/device/gxx-linux/regs/uartregaccessb.cpp index e208543..2d6ed3b 100644 --- a/device/gxx-linux/regs/uartregaccessb.cpp +++ b/device/gxx-linux/regs/uartregaccessb.cpp @@ -2,11 +2,15 @@ #include "uartregaccessb.h" #include "serialib.h" #include "stringex.hpp" +#include UartRegsAccessB::UartRegsAccessB(std::string devName, int bauds, int readflag, int writeflag) { m_serial.reset(new serialib()); - m_serial->Open(devName.c_str(), bauds); + if(m_serial->Open(devName.c_str(), bauds) != 1){ + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + m_serial->Open(devName.c_str(), bauds); + } this->readflag = readflag; this->writeflag = writeflag; } @@ -33,11 +37,10 @@ bool UartRegsAccessB::read(unsigned int addr, unsigned int& val) pdata[0] = readflag; pdata[1] = (unsigned char)addr; m_serial->Write(bufRecv, 2); - if (m_serial->Read(bufRecv, 5, 500)) + if (m_serial->Read(bufRecv, 5, 200)) { val = *((unsigned int*)(bufRecv + 1)); return true; } - return false; } \ No newline at end of file diff --git a/device/gxx-linux/scanner/deviceconfig.cpp b/device/gxx-linux/scanner/deviceconfig.cpp index ff654f9..f4dbae2 100644 --- a/device/gxx-linux/scanner/deviceconfig.cpp +++ b/device/gxx-linux/scanner/deviceconfig.cpp @@ -61,8 +61,11 @@ json DeviceConfig::getdefaultjson() void DeviceConfig::savejson(json js) { + //std::lock_guard lc(m_lock); std::ofstream o(ParamPath); o << std::setw(4) << js <> m_json; + i.close(); return m_json; } diff --git a/device/gxx-linux/scanner/fsmstate.cpp b/device/gxx-linux/scanner/fsmstate.cpp index 57a9f90..526a466 100644 --- a/device/gxx-linux/scanner/fsmstate.cpp +++ b/device/gxx-linux/scanner/fsmstate.cpp @@ -1,7 +1,7 @@ #include "fsmstate.h" -#include "iscanner.h" +#include "scanner.h" -IScanner *FsmState::scanner = NULL; +Scanner *FsmState::scanner = NULL; #ifndef LOG #define LOG printf #endif diff --git a/device/gxx-linux/scanner/fsmstate.h b/device/gxx-linux/scanner/fsmstate.h index 1b8e55d..6091e79 100644 --- a/device/gxx-linux/scanner/fsmstate.h +++ b/device/gxx-linux/scanner/fsmstate.h @@ -4,7 +4,7 @@ #include #include -class IScanner; +class Scanner; enum ScanEvent { @@ -47,12 +47,12 @@ public: virtual FsmState* on_event(ScanEvent event) = 0; virtual void initial() {} - static void setScanner(IScanner* scan) { + static void setScanner(Scanner* scan) { scanner = scan; } std::string typeName = "FsmState"; protected: - static IScanner* scanner; + static Scanner* scanner; }; diff --git a/device/gxx-linux/scanner/iimagehandler.h b/device/gxx-linux/scanner/iimagehandler.h index eaf1c9b..9699441 100644 --- a/device/gxx-linux/scanner/iimagehandler.h +++ b/device/gxx-linux/scanner/iimagehandler.h @@ -16,13 +16,8 @@ static std::map papersize{ {B4, Size{250, 353}}, {B5, Size{176, 250}}, {B6, Size{125, 176}}, -#ifdef G300 - {MaxSize, Size{210, (long)(420 * 1.5)}}, - {USStatement, Size{210, (long)(420 * 1.5)}}, -#else {MaxSize, Size{297, 1040}}, {USStatement, Size{297, (long)(420 * 1.5)}}, -#endif {USLetter, Size{216, 279}}, {USLegal, Size{216, 356}}, {USLedger, Size{279, 432}}, @@ -37,7 +32,7 @@ class IImageHandler { public: virtual ~IImageHandler() {} - virtual void add_image(void *data, int width, int height, int type,int scannnum,std::uint32_t fpga_vs,CISVendor cistype) = 0; + virtual void add_image(void *data, int width, int height, int type,int scannnum,unsigned int fpgaversion=0x00090001) = 0; virtual void config_procparams(HGImgProcParms params) = 0; virtual void add_scanevent(HGIntInfo status) = 0; virtual void clear() = 0; @@ -74,18 +69,14 @@ public: bool set_config(GScanCap config) { - m_hgimgconfig = config; + m_hgimgconfig = config; if(config.resolution_dst<300.0f) m_hgimgconfig.resolution_native = 200.0f; -#ifdef G300 - else - m_hgimgconfig.resolution_native = 300.0f; -#else - else if(config.resolution_dst <500.0f) + else if(config.resolution_dst < 500.0f) m_hgimgconfig.resolution_native = 300.0f; else m_hgimgconfig.resolution_native = 600.0f; -#endif + m_ials.clear(); if(m_dog.get()) { @@ -96,22 +87,26 @@ public: } if(config.fillhole.is_fillhole) { - if((config.fillholeratio_down+config.fillholeratio_up+config.fillholeratio_left+config.fillholeratio_right)>0) + if((config.fillholeratio_down+config.fillholeratio_up+config.fillholeratio_left+config.fillholeratio_right)>0) { m_ials.push_back(std::shared_ptr(new CImageApplyOutHole( 25.0f, {config.fillholeratio_up/100.0f,config.fillholeratio_down/100.0f,config.fillholeratio_left/100.0f,config.fillholeratio_right/100.0f}, 50.0))); + printf(" \nconfig.fillholeratio -----"); } else if(config.fillhole.fillholeratio > 0){ float ratio=config.fillhole.fillholeratio/100.0; m_ials.push_back(std::shared_ptr(new CImageApplyOutHole(25.0f,{ratio,ratio,ratio,ratio},50.0))); } } - bool islongcustomcrop = config.papertype == 52 || config.papertype == 0; + bool islongcustomcrop = config.papertype == 52; //bool isautocrop = config.papertype == TwSS::None; Size fixedSize; - printf(" \nconfig.dogeardistabce=%d", config.dogeardistabce); + printf(" \nconfig.fillholeratio_down=%d", config.fillholeratio_down); + printf(" \nconfig.fillholeratio_up=%d", config.fillholeratio_up); + printf(" \nconfig.fillholeratio_left=%d", config.fillholeratio_left); + printf(" \nconfig.fillholeratio_right=%d", config.fillholeratio_right); printf(" \nconfig.papertype=%d", config.papertype); printf(" \nconfig.AutoCrop_threshold=%d", config.AutoCrop_threshold); printf(" \nconfig.autodescrew=%d", config.autodescrew); @@ -124,12 +119,12 @@ public: printf(" \nconfig.enhance_color=%d", config.enhance_color); printf(" \nconfig.fillbackground=%d", config.fillbackground); printf(" \nconfig.filter=%d", config.filter); + printf(" \nconfig.HsvFilterType=%d", config.HsvFilterType); printf(" \nconfig.fillhole.is_fillhole=%d", config.fillhole.is_fillhole); printf(" \nconfig.gamma=%f", config.gamma); printf(" \nconfig.hardwarecaps.capturepixtype=%d", config.hardwarecaps.capturepixtype); printf(" \nconfig.hardwarecaps.en_doublefeed=%d", config.hardwarecaps.en_doublefeed); printf(" \nconfig.hsvcorrect=%d", config.hsvcorrect); - printf(" \nconfig.HsvFilterType=%d", config.HsvFilterType); printf(" \nconfig.imageRotateDegree=%d", config.imageRotateDegree); printf(" \nconfig.indent=%d", config.indent); printf(" \nconfig.is_autocontrast=%d", config.is_autocontrast); @@ -149,14 +144,12 @@ public: printf(" \nconfig.resolution_dst=%f", config.resolution_dst); printf(" \nconfig.resolution_native=%f", config.resolution_native); printf(" \nconfig.scannum=%d", config.scannum); - printf(" \nconfig.sharpen=%d",config.sharpen); + printf(" \nconfig.sharpen=%d", config.sharpen); printf(" \nconfig.is_dogeardetection=%d", config.is_dogeardetection); fixedSize = GetPaperSize(config.papertype, m_hgimgconfig.resolution_native, config.paperAlign); printf( " \n fixedSize x %d fixedSize y %d ",fixedSize.x,fixedSize.y); - config.is_autocrop = 1; - islongcustomcrop = false; - m_ials.push_back(shared_ptr(new CImageApplyAutoCrop(islongcustomcrop ? islongcustomcrop : config.is_autocrop, - config.autodescrew, config.fillbackground, cv::Size(fixedSize.x, fixedSize.y), config.is_convex,false,config.AutoCrop_threshold,config.noise,config.indent))); + // m_ials.push_back(shared_ptr(new CImageApplyAutoCrop(islongcustomcrop ? islongcustomcrop : config.is_autocrop, + // config.autodescrew, config.fillbackground, cv::Size(fixedSize.x, fixedSize.y), config.is_convex,false,config.AutoCrop_threshold,config.noise,config.indent))); if (config.is_autodiscradblank_normal || config.is_autodiscradblank_vince) { @@ -176,14 +169,13 @@ public: m_ials.push_back(shared_ptr(new CImageApplyCustomCrop(cv::Rect(config.cropRect.x,config.cropRect.y,config.cropRect.width,config.cropRect.height)))); } - m_hgimgconfig.is_colorcast = 0; - // if((config.pixtype == 2)&&(config.is_colorcast)) - // { - // printf("\n 色偏"); - // m_ials.push_back(m_colorcast); - // } + if((config.pixtype == 2)&&(config.is_colorcast)) + { + printf("\n 色偏"); + m_ials.push_back(m_colorcast); + } - // if (config.fadeback && config.pixtype > 0)// && config.pixtype == 2 + if (config.fadeback && config.pixtype > 0)// && config.pixtype == 2 { printf("\n 除底色"); m_ials.push_back(shared_ptr(new CImageApplyFadeBackGroudColor(50,0,config.fadebackrange))); @@ -304,24 +296,21 @@ public: m_ials.push_back(shared_ptr(new CImageApplyConcatenation(CImageApplyConcatenation::ConcatMode(config.fold_concatmode), cv::Scalar(255, 255, 255)))); } - if (config.imageRotateDegree != 0.0 || config.is_backrotate180) { - // CImageApplyRotation::RotationType type; - // if (config.imageRotateDegree > 89.0f && config.imageRotateDegree < 91.0f) - // type = CImageApplyRotation::RotationType::Rotate_90_clockwise; - // else if (config.imageRotateDegree > 269.0f && config.imageRotateDegree < 271.0f) - // type = CImageApplyRotation::RotationType::Rotate_90_anti_clockwise; - // else if (config.imageRotateDegree > 179.0f && config.imageRotateDegree < 181.0f) - // type = CImageApplyRotation::RotationType::Rotate_180; - // else - // type = CImageApplyRotation::RotationType::Invalid; + CImageApplyRotation::RotationType type; + if (config.imageRotateDegree > 89.0f && config.imageRotateDegree < 91.0f) + type = CImageApplyRotation::RotationType::Rotate_90_clockwise; + else if (config.imageRotateDegree > 269.0f && config.imageRotateDegree < 271.0f) + type = CImageApplyRotation::RotationType::Rotate_90_anti_clockwise; + else if (config.imageRotateDegree > 179.0f && config.imageRotateDegree < 181.0f) + type = CImageApplyRotation::RotationType::Rotate_180; + else + type = CImageApplyRotation::RotationType::Invalid; - // m_ials.push_back(shared_ptr(new CImageApplyRotation(type, config.is_backrotate180, config.resolution_dst, NULL))); + m_ials.push_back(shared_ptr(new CImageApplyRotation(type, config.is_backrotate180, config.resolution_dst, NULL))); } - printf("Image processors: %d\n", m_ials.size()); - return true; } @@ -332,5 +321,5 @@ protected: std::vector> m_ials; std::shared_ptr m_dog; std::shared_ptr m_sizedetect; - // std::shared_ptr m_colorcast; + std::shared_ptr m_colorcast; }; diff --git a/device/gxx-linux/scanner/imagesavehandler.cpp b/device/gxx-linux/scanner/imagesavehandler.cpp index be9cda1..80ece6c 100644 --- a/device/gxx-linux/scanner/imagesavehandler.cpp +++ b/device/gxx-linux/scanner/imagesavehandler.cpp @@ -14,7 +14,7 @@ ImageSaveHandler::~ImageSaveHandler() } -void ImageSaveHandler::add_image(void *data, int width, int height, int type, int scannnum,std::uint32_t fpga_vs,CISVendor cistype) +void ImageSaveHandler::add_image(void *data, int width, int height, int type, int scannnum,unsigned int fpgaversion) { static int indexx = 0; std::string path = std::to_string(++indexx) + ".png"; diff --git a/device/gxx-linux/scanner/imagesavehandler.h b/device/gxx-linux/scanner/imagesavehandler.h index 5bf1c81..2082e0b 100644 --- a/device/gxx-linux/scanner/imagesavehandler.h +++ b/device/gxx-linux/scanner/imagesavehandler.h @@ -8,7 +8,7 @@ class ImageSaveHandler : public IImageHandler public: ImageSaveHandler(); virtual ~ImageSaveHandler(); - virtual void add_image(void* data, int width, int height, int type ,int scannnum,std::uint32_t fpga_vs,CISVendor cistype); + virtual void add_image(void* data, int width, int height, int type ,int scannnum,unsigned int fpgaversion); virtual bool done(); private: diff --git a/device/gxx-linux/scanner/imageusbhandler.cpp b/device/gxx-linux/scanner/imageusbhandler.cpp index 7d127ae..0bca491 100644 --- a/device/gxx-linux/scanner/imageusbhandler.cpp +++ b/device/gxx-linux/scanner/imageusbhandler.cpp @@ -10,198 +10,154 @@ #include "imageencode.h" #include #include "ImageApplyAutoCrop.h" +#include "ImageApplyColorCastCorrect.h" #include "hgutils.h" #include "correct_ultis.h" -#include -#include "../usb/src/common/packet.h" -#include "../usb/src/common/sys_util.h" - -namespace bmp -{ -#pragma pack(push) -#pragma pack(1) - typedef struct BITMAPFILEHEADER - { - u_int16_t bfType; - u_int32_t bfSize; - u_int16_t bfReserved1; - u_int16_t bfReserved2; - u_int32_t bfOffBits; - } BITMAPFILEHEADER; - - typedef struct BITMAPINFOHEADER - { - u_int32_t biSize; - u_int32_t biWidth; - u_int32_t biHeight; - u_int16_t biPlanes; - u_int16_t biBitCount; - u_int32_t biCompression; - u_int32_t biSizeImage; - u_int32_t biXPelsPerMeter; - u_int32_t biYPelsPerMeter; - u_int32_t biClrUsed; - u_int32_t biClrImportant; - } BITMAPINFODEADER; -#pragma pack(pop) - - int save_2_bmp_file(const char *bmp_file, void *buf, int w, int h, int resolution) - { - BITMAPINFOHEADER bih = {0}; - BITMAPFILEHEADER fh = {0}; - int pal_size = 0, line_len = (w * 24 + 31) / 32 * 4; - FILE *dst = fopen(bmp_file, "wb"); - - if (!dst) - return errno; - - bih.biSize = sizeof(bih); - bih.biWidth = w; - bih.biBitCount = 24; - bih.biSizeImage = h * line_len; - bih.biPlanes = 1; - bih.biHeight = h; - bih.biCompression = 0; - bih.biXPelsPerMeter = bih.biYPelsPerMeter = resolution * 39.37f + .5f; - - fh.bfType = 'B' | ('M' << 8); - fh.bfOffBits = sizeof(fh) + sizeof(bih) + pal_size; - fh.bfSize = fh.bfOffBits + bih.biSizeImage; - - fwrite(&fh, 1, sizeof(fh), dst); - fflush(dst); - - printf("width * 3 = %d, line bytes = %d\n", w * 3, line_len); - unsigned char *ptr = (unsigned char *)buf; - unsigned int pad = 0; - int pad_l = 4 - ((w * 3) % 4), step = w * 3; - - if (0) - { - ptr += w * 3 * (h - 1); - step *= -1; - } - if (line_len == w * 3) - { - bih.biHeight *= -1; - fwrite(&bih, 1, sizeof(bih), dst); - fwrite(buf, 1, bih.biSizeImage, dst); - } - else - { - fwrite(&bih, 1, sizeof(bih), dst); - for (int i = 0; i < h; ++i) - { - fwrite(ptr, w * 3, 1, dst); - fwrite(&pad, 1, pad_l, dst); - ptr += step; - } - } - fclose(dst); - - return 0; - } - -} static const std::string loggername = "imageusbhandler"; ImageUsbHandler::ImageUsbHandler(std::shared_ptr images) - : pool(1), encodepools(6), pushpool(1), que_len_(0) + : pool(1), encodepools(6),pushpool(1) { LOG_INIT(); this->images = images; - m_dog.reset(new CImageApplyDogEarDetection(40, 1.0, 50)); - // m_colorcast.reset(new CImageApplyColorCastCorrect()); + m_dog.reset(new CImageApplyDogEarDetection(40,1.0,50)); + m_colorcast.reset(new CImageApplyColorCastCorrect(CImageApplyColorCastCorrect::CIS_DN_PATCH1)); m_sizedetect.reset(new CSizedetect(1)); initLut(); - auto info = jsonconfig().getscannerinfo(); - H_ratio = *((float *)(&info.H_ratio)); - V_ratio = *((float *)(&info.V_ratio)); + auto info= jsonconfig().getscannerinfo(); + H_ratio =*((float*)(&info.H_ratio)); + V_ratio =*((float*)(&info.V_ratio)); } ImageUsbHandler::~ImageUsbHandler() { -} -static int push_img_data_times = 0; -static int take_img_data_times = 0; -static int num = 0; -void ImageUsbHandler::add_image(void *data, int width, int height, int type, int scannnum, std::uint32_t fpga_vs, CISVendor cistype) -{ - printf("\nadd_image(%u * %u), memory usage = %s\n", width, height, sys_util::format_readable_bytes(sys_util::get_memory_usage("scan")).c_str()); - - images->push(nullptr, false); - // bmp::save_2_bmp_file((std::string("/root/.scanner/log/cap_") + std::to_string(scannnum) + ".bmp").c_str(), data, width / 3, height, 200); - PACKIMAGE pkimg; +} +static int num = 0; +void ImageUsbHandler::add_image(void *data, int width, int height, int type, int scannnum,unsigned int fpgaversion) +{ + printf("ImageUsbHandler::add_image(%d * %d), fpgaversion = %d\n", width, height, fpgaversion); + + if(images->push_raw(data, width, height, type == CV_8UC1 ? COLOR_CHANNEL_GRAY : COLOR_CHANNEL_RGB, scannnum, fpgaversion, 0)) + { + return; + } - memset(&pkimg, 0, sizeof(pkimg)); - pkimg.pos.paper_ind = scannnum; - pkimg.pos.status = IMG_STATUS_OK; - pkimg.pos.paper_side = PAPER_SIDE_LEFT; + images->push(nullptr, false); // notify ONE paper passed + // img_one_paper *paper = new img_one_paper(); + // paper->init_from(data, width, height, scannnum, PAPER_SIDE_LEFT, type == CV_8UC1 ? COLOR_CHANNEL_GRAY : COLOR_CHANNEL_RGB); + // imgproc_->push_image(paper); + // paper->release(); + std::string ext = ".jpg"; { if (m_imgstatus.status != NO_error) return; cv::Mat mat; - if (m_scanconfig.g200params.dpi == 3) + if(m_scanconfig.g200params.dpi == 3) mat = cv::Mat(height, width, CV_8UC1, data); else - mat = cv::Mat(height, width, CV_8UC1, data).clone(); - printf("Image %d parameters: %d * %d * %d\n", scannnum, mat.cols, mat.rows, mat.channels() * 8); + mat = cv::Mat(height, width, CV_8UC1, data).clone(); capture_data.Put(mat); StopWatch checktime; - add_que_count(); - results.emplace( - pool.enqueue([this, width, height, type, ext, scannnum, data, cistype] - { - printf("\nenqueue image index %d \n",scannnum); - StopWatch sw; - cv::Mat mat = capture_data.Take(); -#ifdef G300 - cv::Mat saveMat = GetStitchMat(type == 16?1:0,width,height,mat); + if (m_hgimgconfig.is_dogeardetection || m_hgimgconfig.en_sizecheck) + { + cv::Mat tmp = cv::Mat(height, width, CV_8UC1, data); + if (tmp.empty()) + return; + m_imgstatus.status = Img_Detecting; + auto mergemat = GetMergeMat(type == CV_8UC1 ? width : width / 3, height, type, tmp,fpgaversion); + if (m_scanconfig.g200params.dpi == 1) + cv::resize(mergemat, mergemat, cv::Size(0, 0), 200.0 / 300.0, 1.0); + else if (m_scanconfig.g200params.dpi == 2) + cv::resize(mergemat, mergemat, cv::Size(0, 0), 200.0 / 300.0, 200.0 / 300.0); + else + { +#ifdef G200 + cv::resize(mergemat,mergemat,cv::Size(0,0),200.0 / 600.0,1.43434/3); #else - int dstwidth = type==CV_8UC1?width:width/3; - cv::Mat saveMat =GetMergeMat(dstwidth, height, type,mat,0x90001); + cv::resize(mergemat,mergemat,cv::Size(0,0),200.0 / 600.0,1.432323/3); #endif - printf("Merged image: %d * %d * %d\n", saveMat.cols, saveMat.rows, saveMat.channels() * 8); - - //printf("\n GetMergeMat time %f \n",sw.elapsed_ms()); - //cv::imwrite("/home/"+to_string(scannnum)+".png",saveMat); - int dpi = saveMat.cols==7344?2:3; + } + + if (m_hgimgconfig.is_dogeardetection) + { + printf("\n is_dogeardetection"); + if(!m_scanconfig.g200params.pc_correct) + correctColor(mergemat, false); + auto dogmat=mergemat(cv::Rect(mergemat.cols/2, 0, mergemat.cols/2, mergemat.rows)); + m_dog->apply(dogmat,0); + if(m_dog->getResult()) + { + m_imgstatus.status=Dog_error; + m_imgstatus.sannum=scannnum; + add_scanevent({.From=IMG,.Code=m_imgstatus.status,.Img_Index=m_imgstatus.sannum}); + return; + } + } + if(m_hgimgconfig.en_sizecheck) + { + auto sizemat=mergemat(cv::Rect(mergemat.cols/2, 0, mergemat.cols/2, mergemat.rows)); + printf("\n en_sizecheck %d",m_scanconfig.g200params.paper); + m_sizedetect->SetPapertype(m_scanconfig.g200params.paper); + if(m_sizedetect->preprocess(sizemat,NULL)) + { + m_imgstatus.status=Size_error; + m_imgstatus.sannum=scannnum; + add_scanevent({.From=IMG,.Code=m_imgstatus.status,.Img_Index=m_imgstatus.sannum}); + return; + } + } + m_imgstatus.status = NO_error; + } + //tmp.release(); + + //std::lock_guard guard(mtx); + results.emplace( + pool.enqueue([this, width, height, type, ext, scannnum, data ,fpgaversion] + { + printf("enqueue image index %d \n",scannnum); + StopWatch sw; + cv::Mat mat = capture_data.Take(); + + int dstwidth = type==CV_8UC1?width:width/3; + static int it=0; + StopWatch sss; + cv::Mat saveMat =GetMergeMat(dstwidth, height, type,mat,fpgaversion); + printf("\n Merge time %f fpgaversion %d \n",sss.elapsed_ms(),fpgaversion); + //cv::imwrite("/home/"+to_string(it++)+".bmp",saveMat); + //int dpi = saveMat.cols==7344?2:3; if(!m_scanconfig.g200params.pc_correct) - correctColor(saveMat,dpi,saveMat.channels()==3?1:0,!m_scanconfig.g200params.is_textcorrect); + correctColor(saveMat,m_scanconfig.g200params.dpi,saveMat.channels()==3?1:0,!m_scanconfig.g200params.is_textcorrect); printf("\n correctColor time %f \n",sw.elapsed_ms()); + + // if((H_ratio != 1.0f) || (V_ratio != 1.0f)) + // cv::resize(saveMat,saveMat,cv::Size(),H_ratio,V_ratio); encode_data.Put(saveMat); - add_que_count(); - encodeimgs.push(encodepools.enqueue([this,width,height,type,cistype]() -> std::vector + + encodeimgs.push(encodepools.enqueue([this,width,height,type]() -> std::vector { - auto saveMat = encode_data.Take(); + auto saveMat = encode_data.Take(); if(H_ratio>1.2f ||H_ratio<0.8f) H_ratio=1.0f; if(V_ratio>1.2f || V_ratio <0.8f) V_ratio=1.0f; - if(m_scanconfig.g200params.dpi==0x01) + if(m_scanconfig.g200params.dpi==1) { - cv::resize(saveMat,saveMat,cv::Size(0,0),200.0/300.0*H_ratio,1.0*V_ratio); + cv::resize(saveMat,saveMat,cv::Size(0,0),200.0/300.0*H_ratio,1.0*V_ratio); } if(m_scanconfig.g200params.dpi == 2) { - if((H_ratio != 1.0f) || (V_ratio != 1.0f)) - cv::resize(saveMat,saveMat,cv::Size(),H_ratio,V_ratio); + if((H_ratio != 1.0f) || (V_ratio != 1.0f)) + cv::resize(saveMat,saveMat,cv::Size(0,0),H_ratio,V_ratio); } if(m_scanconfig.g200params.dpi == 3) -#ifdef G200 - cv::resize(saveMat,saveMat,cv::Size(0,0),1.0*H_ratio,1.43434*V_ratio); // 600 dpi ��������ʵ600�ɼ� -#elif defined G300 + #ifdef G200 + cv::resize(saveMat,saveMat,cv::Size(0,0),1.0*H_ratio,1.43434*V_ratio); // 600 dpi ��������ʵ600�ɼ� + #else cv::resize(saveMat,saveMat,cv::Size(0,0),1.0*H_ratio,1.432323*V_ratio); -#elif defined G400 - cv::resize(saveMat,saveMat,cv::Size(0,0),1.0*H_ratio,1.5*V_ratio); -#else - cv::resize(saveMat,saveMat,cv::Size(0,0),1.0*H_ratio,1.432323*V_ratio); -#endif - printf("dpi = %d, image = %d * %d * %d\n", m_scanconfig.g200params.dpi, saveMat.cols, saveMat.rows, saveMat.channels() * 8); - + #endif cv::Mat imageMat; std::vector imgs; int actwidth = saveMat.cols / 2; @@ -214,14 +170,11 @@ void ImageUsbHandler::add_image(void *data, int width, int height, int type, int imgs.push_back(imageMat); } } - // imgs.push_back(saveMat); - std::shared_ptr imageencode; //(new BmpImageEncode()); - std::vector encodedata; - //bool iscorrect_mode =true; - //if(!iscorrect_mode) + std::shared_ptr imageencode; //(new BmpImageEncode()); + std::vector encodedata; if (!m_scanconfig.g200params.iscorrect_mode) { - if (!m_hgimgconfig.is_switchfrontback && (imgs.size() > 1)) + if (m_hgimgconfig.is_switchfrontback && (imgs.size() > 1)) std::swap(imgs[0], imgs[1]); CImageApply* ptr = m_ials[0].get(); if (typeid(*ptr) != typeid(CImageApplyOutHole)){ @@ -231,15 +184,14 @@ void ImageUsbHandler::add_image(void *data, int width, int height, int type, int cv::flip(imgs[1], imgs[1], 1); } } + for (auto &ialsnode : m_ials) { ialsnode->apply(imgs, bool(m_hgimgconfig.is_duplex)); } - if ((!m_hgimgconfig.is_duplex) && (imgs.size() > 1)) imgs.pop_back(); - else if((imgs.size() > 1) && (cistype == CISVendor::HUALIN_CIS_V0)) - cv::flip(imgs[1], imgs[1], 0); + } for (auto &img : imgs) @@ -255,8 +207,7 @@ void ImageUsbHandler::add_image(void *data, int width, int height, int type, int if(m_scanconfig.g200params.iscorrect_mode) imageencode.reset(new JpegImageEncode(false, m_hgimgconfig.resolution_dst)); else - imageencode.reset(new JpegImageEncode(m_scanconfig.g200params.color?false:true, m_hgimgconfig.resolution_dst)); - + imageencode.reset(new JpegImageEncode(m_hgimgconfig.pixtype == 0, m_hgimgconfig.resolution_dst)); encodedata.push_back(imageencode->encode(enMat)); } } @@ -270,28 +221,18 @@ void ImageUsbHandler::add_image(void *data, int width, int height, int type, int for (auto &data : mem) { if (data.get()) - { - images->push(data, true); - } - + images->push(data, true); else add_scanevent({.From = V4L2, .Code = 1}); } } - else - printf("!!!!!!!!! mem proc = empty vector \n"); - - add_que_count(-1); }); - //printf("imgproce time = %f \n", sw.elapsed_ms()); - //LOG_TRACE(string_format("imgproce time = %f\n", sw.elapsed_ms())); - })); - add_que_count(-1); + printf("imgproce time = %f \n", sw.elapsed_ms()); + LOG_TRACE(string_format("imgproce time = %f\n", sw.elapsed_ms())); })); } } -bool ImageUsbHandler::is_limit() -{ +bool ImageUsbHandler::is_limit(){ if (m_hgimgconfig.resolution_dst > 200.0 || m_hgimgconfig.papertype == 52 || m_hgimgconfig.papertype == 54 || m_hgimgconfig.papertype == 131) { @@ -299,7 +240,7 @@ bool ImageUsbHandler::is_limit() { results.front().get(); { - // std::lock_guard guard(mtx); + //std::lock_guard guard(mtx); results.pop(); } } @@ -310,62 +251,31 @@ bool ImageUsbHandler::is_limit() } else { - while (results.size() >= 20) + while (results.size() >= 15) { results.front().get(); { - // std::lock_guard guard(mtx); + //std::lock_guard guard(mtx); results.pop(); } } - if (encodeimgs.size() >= 20) + if (encodeimgs.size() >= 15) { + //printf("\n encodeimgs size = %d ", encodeimgs.size()); return true; } } return false; } -void ImageUsbHandler::thread_push_stop_event(HGIntInfo ev) -{ - printf("Received STOPSCAN event, but image-process is busying, wait real stop in thread ...\n"); - while (!done()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(3)); - } - push_event(ev); -} -void ImageUsbHandler::push_event(HGIntInfo ev) +void ImageUsbHandler::add_scanevent(HGIntInfo status) { VectorMemroyPtr mem = VectorMemroyPtr(new VectorMemroy()); - HGIntInfo info = ev; + HGIntInfo info = status; mem->resize(sizeof(info)); memcpy(&mem->buf()[0], &info, sizeof(info)); images->push(mem, false); } -int32_t ImageUsbHandler::add_que_count(int adden) -{ - std::lock_guard lock(proc_que_); - - que_len_ += adden; - - return que_len_; -} - -void ImageUsbHandler::add_scanevent(HGIntInfo status) -{ - printf("add_scanevent(%d)\n", status.From); - if (status.From == STOPSCAN && !done()) - { - if (stop_event_thread_.get() && stop_event_thread_->joinable()) - stop_event_thread_->join(); - stop_event_thread_.reset(new std::thread(&ImageUsbHandler::thread_push_stop_event, this, status)); - } - else - { - push_event(status); - } -} void ImageUsbHandler::clear() { @@ -378,40 +288,14 @@ void ImageUsbHandler::clear() capture_data.Clear(); } -void ImageUsbHandler::Set_ratio(u32 h_ratio, u32 v_ratio) +void ImageUsbHandler::Set_ratio(u32 h_ratio,u32 v_ratio) { - H_ratio = *((float *)(&h_ratio)); - // V_ratio =*((float*)(&v_ratio)); - V_ratio = 1.0f; + H_ratio =*((float*)(&h_ratio)); + V_ratio =*((float*)(&v_ratio)); } bool ImageUsbHandler::done() { - // return add_que_count(0) == 0; - - // bool over = true; - // { - // std::lock_guard guard(mtx); - // if (results.size() >= 1) - // { - // auto &fu_run = results.back(); - // if ((fu_run.valid() && (fu_run.wait_for(std::chrono::seconds(0)) != std::future_status::ready))) - // over = false; - // } - // if (over && encodeimgs.size() >= 1) - // { - // auto &fu_encode = encodeimgs.back(); - // over = !fu_encode.valid() || encodeimgs.size() == 0; - // // if((!fu_encode.valid()) && encodeimgs.size() == 1) - // // over = true; - // // else - // // over = false; - // // return !(fu_encode.wait_for(std::chrono::seconds(0)) != std::future_status::ready); - // // return (!(fu_run.wait_for(std::chrono::seconds(0)) != std::future_status::ready))&&(!(fu_encode.wait_for(std::chrono::seconds(0)) != std::future_status::ready)); - // } - // } - - // return over; std::lock_guard guard(mtx); if(results.size() >= 1){ auto &fu_run = results.back(); @@ -427,7 +311,6 @@ bool ImageUsbHandler::done() return false; return !(fu_encode.wait_for(std::chrono::seconds(0)) != std::future_status::ready); //return (!(fu_run.wait_for(std::chrono::seconds(0)) != std::future_status::ready))&&(!(fu_encode.wait_for(std::chrono::seconds(0)) != std::future_status::ready)); - } return true; } @@ -443,61 +326,3 @@ void ImageUsbHandler::config_procparams(HGImgProcParms params) LOG_TRACE(string_format("HGImgProcParms.fillhole = %d \n", params.imgprocparams.fillhole)); m_procparams = params; } - -//{ -// "montage": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 10, -// "unit" : "None", -// "title" : "图像拼接", -// "desc" : "将CIS采集的原始数据恢复为正常的图像", -// "type" : "bool", -// "cur" : true, -// "default" : true, -// "size" : 4, -// }, -// "fb-split": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 20, -// "unit" : "None", -// "title" : "拆分正反面", -// "desc" : "将正反面合成的一张图片,拆分成正面和反面图片", -// "type" : "bool", -// "cur" : true, -// "default" : true, -// "size" : 4, -// "depend_and": ["montage==true"] -// } -//} -// -// -// -//{ -// "compress": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "imgproc", -// "pos" : 9999, -// "unit" : "None", -// "title" : "图像压缩", -// "desc" : "图片压缩成指定文件格式", -// "type" : "string", -// "cur" : "jpeg", -// "default" : "jpeg", -// "size" : 32, -// "range": ["none", "zip", "jpeg", "png", "bmp"] // none & zip 方式的数据为PACKIMAGE + 图像点阵数据 -// } -//} diff --git a/device/gxx-linux/scanner/imageusbhandler.h b/device/gxx-linux/scanner/imageusbhandler.h index b424955..1afa01d 100644 --- a/device/gxx-linux/scanner/imageusbhandler.h +++ b/device/gxx-linux/scanner/imageusbhandler.h @@ -9,22 +9,17 @@ class UsbImageProcQueue; +class img_processor; class ImageUsbHandler: public IImageHandler { - void push_event(HGIntInfo ev); - void thread_push_stop_event(HGIntInfo ev); - int32_t add_que_count(int adden = 1); - - std::shared_ptr stop_event_thread_; - std::mutex proc_que_; - volatile int32_t que_len_; - + img_processor* imgproc_; + public: ImageUsbHandler(std::shared_ptr images = nullptr); virtual ~ImageUsbHandler(); virtual void config_procparams(HGImgProcParms params); - virtual void add_image(void* data, int width, int height, int type,int scannnum,std::uint32_t fpga_vs,CISVendor cistype); + virtual void add_image(void* data, int width, int height, int type,int scannnum,unsigned int fpgaversion) override; virtual void add_scanevent(HGIntInfo status); virtual bool done(); virtual void clear(); diff --git a/device/gxx-linux/scanner/imageusbtesthandler.cpp b/device/gxx-linux/scanner/imageusbtesthandler.cpp index 2ebd7bc..7b6d616 100644 --- a/device/gxx-linux/scanner/imageusbtesthandler.cpp +++ b/device/gxx-linux/scanner/imageusbtesthandler.cpp @@ -14,7 +14,7 @@ ImageUsbTestHandler::ImageUsbTestHandler(std::shared_ptr imag { } -void ImageUsbTestHandler::add_image(void* data, int width, int height, int type ,int scannnum,std::uint32_t fpga_vs,CISVendor cistype) +void ImageUsbTestHandler::add_image(void* data, int width, int height, int type ,int scannnum,unsigned int fpgaversion) { // results.emplace_back( // pool.enqueue([this, data, width, height, type] diff --git a/device/gxx-linux/scanner/imageusbtesthandler.h b/device/gxx-linux/scanner/imageusbtesthandler.h index 7d87b5d..af18a83 100644 --- a/device/gxx-linux/scanner/imageusbtesthandler.h +++ b/device/gxx-linux/scanner/imageusbtesthandler.h @@ -6,5 +6,5 @@ class ImageUsbTestHandler : public ImageUsbHandler { public: ImageUsbTestHandler(std::shared_ptr images = nullptr); - virtual void add_image(void* data, int width, int height, int type,int scannnum,std::uint32_t fpga_vs,CISVendor cistype); + virtual void add_image(void* data, int width, int height, int type,int scannnum,unsigned int fpgaversion); }; \ No newline at end of file diff --git a/device/gxx-linux/scanner/iscanner.cpp b/device/gxx-linux/scanner/iscanner.cpp deleted file mode 100644 index 4c1cef0..0000000 --- a/device/gxx-linux/scanner/iscanner.cpp +++ /dev/null @@ -1,344 +0,0 @@ -#include "iscanner.h" -#include -#include "Imotorboard.h" -#include "Capturer.h" -#include -#include "StopWatch.h" -#include "iimagehandler.h" -#include "correct_ultis.h" -#include "applog.h" -#include "stringex.hpp" -#include "fpgacontrol.h" -#include "scannerregs.h" -#include "fpgacontrol.h" -#include "Gpio.h" -#include "deviceconfig.h" -#include -#include -#include -#include - -static const std::string loggername = "IScanner"; - -IScanner::IScanner(std::shared_ptr capturer, std::shared_ptr mb, std::shared_ptr wake) - : bMsgLoop(true), - scancount(1024) -// testGpio(new Gpio(153)) -{ - LOG_INIT(); - this->wake = wake; - this->mb = mb; - this->capturer = capturer; - mb->set_capture(capturer); - scannerinfo = getscannerinfo(); - auto capturecallback = [&](int cap_call_code, std::string s_info) - { - HGIntInfo info = {.From = AutoCorrect, .Code = cap_call_code, .Img_Index = s_info.length()}; - imagehandler->add_scanevent(info); - if (s_info.length() > 0) - ((ScannerRegAccess *)m_parent)->write_info(s_info); - }; - this->capturer->setcapturecall(capturecallback); -} - -IScanner::~IScanner() -{ - bMsgLoop = false; - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - sysEvent.Put(ScanEvent::S_EVT_STOP_SCAN); - - if (threadRunMessageLoop.joinable()) - threadRunMessageLoop.join(); -} -bool IScanner::check_scan(std::string encodehexstr){ - bool is_scan = true; - if(DeviceConfig().GetParam().is_lock) - { - auto tmp_token = DeviceConfig().GetParam().token; - if((encodehexstr.length() != 32) || (tmp_token.length() !=32)) - is_scan = false; - else{ - AES_KEY aes_key; - std::uint8_t key[16] ={0}; - //tmp_token = "C34E58CD5F3F2FF703E1AA24892FBD69"; - printf("tmp_token %s",tmp_token); - for(int i =0;i<16;i++) - { - key[i] = std::strtol(tmp_token.substr(i*2,2).c_str(),nullptr,16); - } - if(AES_set_decrypt_key(key,128,&aes_key)< 0) - { - is_scan = false; - } - std::uint8_t cipher[16] ={0}; - std::uint8_t decode[16] ={0}; - for(int i =0;i<16;i++) - { - cipher[i] = std::strtol(encodehexstr.substr(i*2,2).c_str(),nullptr,16); - } - - AES_ecb_encrypt(cipher,decode,&aes_key,AES_DECRYPT); - for(int i =0;iadd_scanevent({.From = MtBoard, 0x100}); - if (m_config.g200params.is_autopaper) - imagehandler->add_scanevent({.From = STOPSCAN, 1}); - imagehandler->add_scanevent({.From = STOPSCAN, 0}); - } - return is_scan; -} - -std::string IScanner::getmbversion() -{ - return mbversion; -} - -void IScanner::add_scansever(HGIntInfo event) -{ - if (imagehandler.get()) - imagehandler->add_scanevent(event); -} - -bool IScanner::set_hgimgconfig(GScanCap config) -{ - printf("enter config set_hgimgconfig \n"); - scancount = config.is_duplex ? config.scannum / 2 : config.scannum; - m_cap = config; - mb->set_scancap(config); - if(config.resolution_dst < 300) - m_config.g200params.dpi = 1; -#ifdef G300 - else - m_config.g200params.dpi = 2; -#else - else if ((config.resolution_dst >= 300) &&(config.resolution_dst < 500)) - m_config.g200params.dpi = 2; - else - m_config.g200params.dpi = 3; -#endif - if(config.HsvFilterType!=0 || config.filter!=3 ||config.fadeback!=0) - m_config.g200params.color = 1; - - printf("\n m_config.g200params.dpi =%d",m_config.g200params.dpi); - imagehandler->set_scanconfig(m_config); - if (config.is_autocrop && (config.papertype == 0)&&m_config.g200params.en_autosize) - m_config.g200params.paper = 16; - if(config.papertype == 54) - m_config.g200params.paper = m_config.g200params.en_autosize? 16 : 17; - if(config.papertype == 52 || config.papertype == 131) - m_config.g200params.paper = m_config.g200params.en_autosize? 16 : 18; - if (imagehandler.get()) - { - imagehandler->clear(); - return imagehandler->set_config(config); - } - return false; -} - -void IScanner::configparam(HGScanConfig config) -{ - LOG_TRACE(string_format("******HGScanConfig******\n config.g200params.color = %d \n config.g200params.dpi = %d \n config.g200params.paper =%d \n config.g200params.double_feed_enbale = %d \n config.g200params.stable_enbale = %d \n config.g200params.iscorrect_mode = %d \n config.g200params.pc_correct = %d\n ", - config.g200params.color, - config.g200params.dpi, - config.g200params.paper, - config.g200params.double_feed_enbale, - config.g200params.stable_enbale, - config.g200params.iscorrect_mode, - config.g200params.pc_correct)); - printf("******HGScanConfig******\n config.g200params.color = %d \n config.g200params.dpi = %d \n config.g200params.paper =%d \n config.g200params.double_feed_enbale = %d \n config.g200params.stable_enbale = %d \n config.g200params.iscorrect_mode = %d \n config.g200params.pc_correct = %d\n ", - config.g200params.color, - config.g200params.dpi, - config.g200params.paper, - config.g200params.double_feed_enbale, - config.g200params.stable_enbale, - config.g200params.iscorrect_mode, - config.g200params.pc_correct); - imagehandler->set_scanconfig(config); - m_config = config; - if (config.g200params.iscorrect_mode) - { - scancount = 65535; - } -} - - - -int IScanner::getimageprocedone() -{ - if (imagehandler.get()) - return imagehandler->done(); - return true; -} - -void IScanner::test_autocorrect(int colormode) -{ - printf("color mode =%s \n", colormode == 1 ? "COLOR" : "GRAY"); - capturer->init_autocorrect(colormode); -} -bool IScanner::is_runscan() -{ - return (fu_runscan && fu_runscan->is_runing()) || (imagehandler && !imagehandler->done()); -} - -void IScanner::set_imagehandler(std::shared_ptr handler) -{ - imagehandler = handler; -} - -void IScanner::clear_error() -{ - mb->clear_error(); -} - -void IScanner::runMessageLoop() -{ - FsmState *fsmState = FsmStateManagerEx::GetState(); - FsmState::setScanner(this); - do - { - ScanEvent evt = sysEvent.Take(); - fsmState = fsmState->on_event(evt); - } while (bMsgLoop); -} - -bool IScanner::paper_ready() -{ - return mb->paper_ready(); -} - -bool IScanner::get_keeplastpaper() -{ - return mb->get_keeplastpaper(); -} - -void IScanner::startcapimage() -{ - FILE * fp =fopen("/sys/class/tty/ttyUSB0/device/huagao_scanner","w"); - if (fp == NULL) - perror("startcapimage open filed"); - else - fprintf(fp,"%d",1); - - fclose(fp); -} - -void IScanner::set_motorboardcallback(MotorBoardGlue glue) -{ - - mb->set_callbacks(glue); -} - -void IScanner::set_imgprocparams(HGImgProcParms params) -{ - imagehandler->config_procparams(params); -} - -void IScanner::test_cap(HGScanConfig config) -{ - printf("capturer openning \n"); - FPGAConfigParam fpgaparam = GetFpgaparam(m_config.g200params.dpi, m_config.g200params.color); - capturer->open(config,fpgaparam); - capturer->snap(); - void *data; - if (data = capturer->readFrame(2000)) - { - int imtype = capturer->color() ? CV_8UC3 : CV_8UC1; - cv::Mat mat; - cv::Mat saveMat; - std::vector ch_mats; - int dstwidth, dstheight; - int width = capturer->width(); - int height = capturer->height(); - dstwidth = width * 3; - dstheight = height / 3; - - if (imtype == CV_8UC3) - { - mat = cv::Mat(height / 3, width * 9, CV_8UC1, data); - saveMat = cv::Mat(dstheight, dstwidth, CV_8UC3); - } - - else - { // gray - saveMat = cv::Mat(height, width * 3, CV_8UC1, data); - } - static int savenum; - if (imtype == CV_8UC3) - { - for (int i = 0; i < 3; i++) - { // B G R - cv::Mat mattemp = mat(cv::Rect(dstwidth * i, 0, dstwidth, dstheight)); - ch_mats.push_back(mattemp); - } - swap(ch_mats[1], ch_mats[2]); - cv::merge(ch_mats, saveMat); - } - //cv::imwrite(std::to_string(++savenum) + ".jpg", saveMat); - } - else - { - printf("LOST Image \n"); - } - capturer->close(); - printf("capturer closed \n"); -} -void IScanner::set_sleeptime(int val) -{ - if (wake.get()) - wake->settime(val); -} - -int IScanner::get_sleeptime() -{ - if (wake.get()) - return wake->gettime(); - return 0; -} - -void IScanner::resettime() -{ - if (wake.get()) - wake->resettime(); -} - -int IScanner::get_sleepstatus() -{ - if (wake.get()) - return wake->get_status(); - return 0; -} - -void IScanner::set_paprent(void *parent) -{ - if (parent) - m_parent = parent; -} -void IScanner::set_sleepstatus(bool off) -{ - if (wake.get()) - { - if (off) - wake->power_on(); - else - wake->power_off(); - } -} - - -void IScanner::clean_paper_road(){ - if(mb.get()) - mb->clean_paper_road(); -} \ No newline at end of file diff --git a/device/gxx-linux/scanner/iscanner.h b/device/gxx-linux/scanner/iscanner.h index 5abc5ff..8c44b23 100644 --- a/device/gxx-linux/scanner/iscanner.h +++ b/device/gxx-linux/scanner/iscanner.h @@ -1,71 +1,45 @@ #pragma once #include -#include +#include +#include "commondef.h" #include "BlockingQueue.h" #include "fsmstate.h" -#include -#include "commondef.h" -#include "wakeup.hpp" -#include - -class IMotorBoard; -class ICapturer; class IImageHandler; -class Gpio; class IScanner { public: - IScanner(std::shared_ptr capturer, std::shared_ptr mb, std::shared_ptr wake); - virtual ~IScanner(); - virtual void start_scan() = 0; - virtual void stop_scan() = 0; - virtual int count() = 0; - virtual int mode() = 0; - virtual int getmbstatus() = 0; - virtual bool getpaperon() = 0; - virtual void runScan() = 0; - void clean_paper_road(); - bool check_scan(std::string encodehexstr); - void configparam(HGScanConfig config); - void put(ScanEvent evt) { sysEvent.Put(evt); } - bool is_runscan(); - void set_imagehandler(std::shared_ptr handler = nullptr); - void clear_error(); - bool paper_ready(); - bool get_keeplastpaper(); - void set_motorboardcallback(MotorBoardGlue glue); - void set_imgprocparams(HGImgProcParms parmas); - void test_autocorrect(int colormode); - void test_cap(HGScanConfig config); - bool set_hgimgconfig(GScanCap config); - void add_scansever(HGIntInfo event); - void set_sleeptime(int val); - int get_sleeptime(); - void resettime(); - int get_sleepstatus(); - void set_sleepstatus(bool off); - int getimageprocedone(); - void set_paprent(void* parent); - std::string getmbversion(); - void runMessageLoop(); - void startcapimage(); -protected: - std::thread threadRunMessageLoop; - volatile bool bMsgLoop = true; - BlockingQueue sysEvent; - std::shared_ptr mb; - std::shared_ptr capturer; - std::shared_ptr wake; - std::shared_ptr fu_runscan; - std::shared_ptr m_capturereload; - std::shared_ptr imagehandler; - std::function m_mtcallback; - int scancount=0; - HGScanConfig m_config; - GScanCap m_cap; - ScannerNativeParam scannerinfo; - void* m_parent; - std::string mbversion; + virtual ~IScanner(){} + virtual void try_scan(const std::string encodehexstr) = 0; + virtual void configparam(HGScanConfig config)=0; + virtual void start_scan()=0; + virtual void stop_scan()=0; + virtual int count()=0; + virtual int mode()=0; + virtual void put(ScanEvent evt)=0; + virtual bool is_runscan()=0; + virtual void set_imagehandler(std::shared_ptr handler = nullptr)=0; + virtual void clear_error()=0; + virtual bool paper_ready()=0; + virtual bool get_keeplastpaper()=0; + virtual void set_motorboardcallback(MotorBoardGlue glue)=0; + virtual void set_imgprocparams(HGImgProcParms parmas)=0; + virtual void test_autocorrect(int colormode)=0; + virtual void test_cap(HGScanConfig config)=0; + virtual bool set_hgimgconfig(GScanCap config)=0; + virtual void add_scansever(HGIntInfo event)=0; + virtual void set_sleeptime(int val)=0; + virtual int get_sleeptime()=0; + virtual void resettime()=0; + virtual int get_sleepstatus()=0; + virtual void set_sleepstatus(bool off)=0; + virtual int getimageprocedone()=0; + virtual void set_paprent(void* parent)=0; + virtual bool getpaperon()=0; + virtual int getmbstatus()=0; + virtual void setfeedmode(int value)=0; + virtual void settrayposition(int value)=0; + virtual std::string getmbversion()=0; + virtual void clean_paper_road() = 0; }; diff --git a/device/gxx-linux/scanner/scanner.cpp b/device/gxx-linux/scanner/scanner.cpp index abbf90b..821694c 100644 --- a/device/gxx-linux/scanner/scanner.cpp +++ b/device/gxx-linux/scanner/scanner.cpp @@ -1,6 +1,6 @@ #include "scanner.h" #include -#include "Imotorboard.h" +#include "motorboard.h" #include "Capturer.h" #include #include "StopWatch.h" @@ -10,14 +10,33 @@ #include "fpgacontrol.h" #include "scannerregs.h" #include "fpgacontrol.h" -#include "Gpio.h" +#include "Displaydef.h" +#include "CImageMerge.h" #include "correct_ultis.h" +#include "SysInforTool.h" +#include "MotorboardParam.h" +#include "FeedControl.h" +#include "deviceconfig.h" +#include +#include +#include +#include static const std::string loggername = "Scanner"; -Scanner::Scanner(std::shared_ptr capturer, std::shared_ptr mb, std::shared_ptr wake):IScanner(capturer,mb,wake) +Scanner::Scanner(std::shared_ptr capturer, std::shared_ptr mb, std::shared_ptr wake) + : bMsgLoop(true), + scancount(1024), + mfpgaversion(0x00090001) { LOG_INIT(); + this->wake = wake; + this->mb = mb; + this->capturer = capturer; + capturer->regs()->read(15, mfpgaversion); + cout << "mfpgaversion :" << mfpgaversion << endl; + SysInforTool(ScannerSysInfo()).GetSysInfo(); + // threadRunMessageLoop = std::move(std::thread(&Scanner::runMessageLoop, this)); auto mb_error_call = [&](unsigned int error_code) { int code = 0; @@ -35,16 +54,19 @@ Scanner::Scanner(std::shared_ptr capturer, std::shared_ptr capturer, std::shared_ptradd_scanevent(errType); + if (imagehandler.get()) + imagehandler->add_scanevent(errType); done_scan = 1; } - - mb_error_code = code; - if (code != 0) - done_scan = 1; + mb_error_code = error_code; }; auto mb_scandone_call = [&]() { done_scan = 1; + if(mb_error_code == 0) + mb_error_code = 0xffffffff; printf("motorboard callback scan_done"); + imagehandler->add_scanevent({.From = STOPSCAN, .Code = mb_error_code}); }; auto mb_osmode_call = [&](unsigned int osmode) @@ -92,6 +115,22 @@ Scanner::Scanner(std::shared_ptr capturer, std::shared_ptradd_scanevent(errType); + done_scan = 1; + } + else + { + printf("\n cover closed "); + LOG_TRACE("cover closed \n"); + } + }; auto mb_set_sleeptime_call = [&](unsigned int speedmode) { printf("\n mb_set_sleeptime_call val= %d ", speedmode); @@ -131,47 +170,246 @@ Scanner::Scanner(std::shared_ptr capturer, std::shared_ptris_runing()) return; start_scan(); }; - MotorBoardGlue mb_glue = {mb_error_call, mb_scandone_call, mb_osmode_call, mb_set_sleeptime_call, mb_mltop_call, mb_auto_paper}; + + MotorBoardGlue mb_glue = {mb_error_call, mb_scandone_call, mb_osmode_call, mb_set_sleeptime_call, mb_mltop_call, mb_auto_paper, mb_coveropen_call}; mb->set_callbacks(mb_glue); - mb->set_auto_paper(m_config.g200params.is_autopaper); //防止程序异常死掉后未关闭连续扫描导致升降台抬升扫描 + mb->PutMsg(DisType::Dis_Idel, 0, ClearScreen::All); + scannerinfo = getscannerinfo(); + auto capturecallback = [&](int cap_call_code, std::string s_info) + { + HGIntInfo info = {.From = AutoCorrect, .Code = cap_call_code, .Img_Index = s_info.length()}; + if (imagehandler.get()) + imagehandler->add_scanevent(info); + if (s_info.length() > 0) + ((ScannerRegAccess *)m_parent)->write_info(s_info); + }; + this->capturer->setcapturecall(capturecallback); + mb->set_auto_paper(false, false); //防止程序异常死掉后未关闭连续扫描导致升降台抬升扫描 + mb->setautopaperkeystopcallback([&]{ + if (m_config.g200params.is_autopaper) + imagehandler ? imagehandler->add_scanevent({.From = STOPSCAN, 1}) : void(0); + handstop = true; }); + // mb->set_speed_mode(2); u32 value; mb->read(0x00, value); printf("mb reg[0] = %d \n", value); value = 0; mb->read(0x03, value); - if (value >= 35211210) - m_mbver = MotorVersion::Motor_paperout; - else if(value >= 35211126) - m_mbver = MotorVersion::Motor_mltop; - else - m_mbver = MotorVersion::Motor_old; mbversion = std::to_string(value); - printf("mb reg[0] = %d \n", value); + printf("mb reg[3] = %d \n", value); } Scanner::~Scanner() { + bMsgLoop = false; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + sysEvent.Put(ScanEvent::S_EVT_STOP_SCAN); + if (threadRunMessageLoop.joinable()) + threadRunMessageLoop.join(); +} + +std::string Scanner::getmbversion() +{ + u32 value = 0; + mb->read(0x03, value); + mbversion = std::to_string(value); + return mbversion; +} + +void Scanner::startcapimage(bool value) +{ + FILE *fp = fopen("/sys/class/tty/ttyUSB0/device/huagao_scanner", "w"); + if (fp == NULL) + perror("startcapimage open filed"); + else + { + fprintf(fp, "%d", value ? 1 : 0); + fclose(fp); + } +} + +bool Scanner::getcapimageflag() +{ + int ret = 1; + FILE *fp = fopen("/sys/class/tty/ttyUSB0/device/huagao_scanner", "r"); + if (fp == NULL) + perror("startcapimage open filed"); + else + { + fscanf(fp, "%d", &ret); + fclose(fp); + } + printf("\ngetcapimageflag %d", ret); + return ret == 0 ? false : true; +} + +void Scanner::add_scansever(HGIntInfo event) +{ + if (imagehandler.get()) + imagehandler->add_scanevent(event); +} + +bool Scanner::set_hgimgconfig(GScanCap config) +{ + printf("enter config set_hgimgconfig \n"); + scancount = config.is_duplex ? config.scannum / 2 : config.scannum; + m_cap = config; + if (config.resolution_dst < 300) + m_config.g200params.dpi = 1; + else if (config.resolution_dst < 500) + m_config.g200params.dpi = 2; + else + m_config.g200params.dpi = 3; + + if(config.HsvFilterType!=0 || config.filter!=3 ||config.fadeback!=0) + m_config.g200params.color = 1; + printf("\n m_config.g200params.dpi =%d", m_config.g200params.dpi); + imagehandler->set_scanconfig(m_config); + if (config.is_autocrop && (config.papertype == 0) && m_config.g200params.en_autosize) + m_config.g200params.paper = 16; + if (config.papertype == 54) + m_config.g200params.paper = m_config.g200params.en_autosize ? 16 : 17; + if (config.papertype == 52 || config.papertype == 131) + m_config.g200params.paper = m_config.g200params.en_autosize ? 16 : 18; + printf("\n ********m_config.g200params.paper %d", m_config.g200params.paper); + if (imagehandler.get()) + { + imagehandler->clear(); + return imagehandler->set_config(config); + } + printf("\n done setting set_hgimgconfig"); + return false; +} + +void Scanner::configparam(HGScanConfig config) +{ + LOG_TRACE(string_format("******HGScanConfig******\n config.g200params.color = %d \n config.g200params.dpi = %d \n config.g200params.paper =%d \n config.g200params.double_feed_enbale = %d \n config.g200params.stable_enbale = %d \n config.g200params.iscorrect_mode = %d \n config.g200params.pc_correct = %d\n ", + config.g200params.color, + config.g200params.dpi, + config.g200params.paper, + config.g200params.double_feed_enbale, + config.g200params.stable_enbale, + config.g200params.iscorrect_mode, + config.g200params.pc_correct)); + printf("******HGScanConfig******\n config.g200params.color = %d \n config.g200params.dpi = %d \n config.g200params.paper =%d \n config.g200params.double_feed_enbale = %d \n config.g200params.stable_enbale = %d \n config.g200params.iscorrect_mode = %d \n config.g200params.pc_correct = %d\n ", + config.g200params.color, + config.g200params.dpi, + config.g200params.paper, + config.g200params.double_feed_enbale, + config.g200params.stable_enbale, + config.g200params.iscorrect_mode, + config.g200params.pc_correct); + imagehandler->set_scanconfig(config); + m_config = config; + if (config.g200params.iscorrect_mode) + { + scancount = 65535; + } + printf("\nconfigparam done\n"); +} + +void Scanner::try_scan(const std::string encodehexstr) +{ + bool is_scan = true; + printf("\n encodehexstr = "); + for(int i =0;iadd_scanevent({.From = MtBoard, 0x100}); + if (m_config.g200params.is_autopaper) + imagehandler->add_scanevent({.From = STOPSCAN, 1}); + imagehandler->add_scanevent({.From = STOPSCAN, 0}); + mb->PutMsg(DisType::Dis_Device_Lock, 0, ClearScreen::All); + } } void Scanner::start_scan() { - printf("\n ------------------start_scan------------------ \n"); - if (is_runscan()) + printf("\n ------------------m_config.g200params.paper %d", m_config.g200params.paper); + LOG_TRACE("\n ------------------start_scan------------------ \n"); + capturer->regs()->read(15, mfpgaversion); + cout << "start_scan mfpgaversion :" << mfpgaversion << endl; + if (m_capturereload && m_capturereload->is_runing()) + { + while (m_capturereload->is_runing()) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + m_capturereload.reset(); + } + if (fu_runscan && fu_runscan->is_runing()) + { + if (m_config.g200params.is_autopaper) + imagehandler->add_scanevent({.From = STOPSCAN, 1}); return; + } if (wake.get()) wake->setsleepfalg(true); - mb_error_code = is_ml_top = handstop = false; + mb->SetKeyState(true); + is_ml_top = handstop = false; + mb_error_code = 0; FPGAConfigParam fpgaparam = GetFpgaparam(m_config.g200params.dpi, m_config.g200params.color); capturer->open(m_config,fpgaparam); + + if (m_config.g200params.is_autopaper) + scancount = 65536; + unsigned int reg0; + mb->read(0x00, reg0); + SMBCONFIG *smb_config = (SMBCONFIG *)®0; + smb_config->dpi_mode = m_config.g200params.dpi -1; + printf(" \n smb_config->dpi_mode =%d ", smb_config->dpi_mode); + mb->write(0x00, reg0); scannerinfo = getscannerinfo(); + imagehandler->Set_ratio(fpgaparam.HRatio, fpgaparam.VRatio); int spdmode = 0; if (scannerSp.count((SpeedMode)scannerinfo.speedmode) <= 0) { @@ -182,11 +420,10 @@ void Scanner::start_scan() #endif } else - { spdmode = scannerSp[(SpeedMode)scannerinfo.speedmode].motorSpeed; - } - mb->set_speed_mode(spdmode,1,1); - printf("\n set speedmode %d read speedmode %d", spdmode, mb->get_speed_mode()); + mb->set_speed_mode(spdmode); + printf("set speedmode %d read speedmode %d \n", spdmode, mb->get_speed_mode()); + // capturer->open(); imagehandler->resetimgstatus(); mb->clear_error(); fu_runscan.reset(new ThreadEx(&Scanner::runScan, this)); @@ -194,10 +431,11 @@ void Scanner::start_scan() void Scanner::stop_scan() { - mb->stop(); handstop = true; + printf("\n hand stop scan"); + mb->stop(); if (m_config.g200params.is_autopaper == 1) - mb->set_auto_paper(false); + mb->set_auto_paper(false, false); } int Scanner::count() @@ -209,6 +447,14 @@ int Scanner::mode() { return mb->os_mode(); } + +int Scanner::getimageprocedone() +{ + if (imagehandler.get()) + return imagehandler->done(); + return true; +} + int Scanner::getmbstatus() { mb->clear_error(); @@ -218,139 +464,552 @@ int Scanner::getmbstatus() return val & 0x700fe; } +void Scanner::test_autocorrect(int colormode) +{ + printf("color mode =%s \n", colormode == 1 ? "COLOR" : "GRAY"); + capturer->init_autocorrect(colormode); +} +bool Scanner::is_runscan() +{ + return (imagehandler && !imagehandler->done()); + // return (fu_runscan && fu_runscan->is_runing()) || (imagehandler && !imagehandler->done()); +} + +void Scanner::set_imagehandler(std::shared_ptr handler) +{ + imagehandler.reset(); + imagehandler = handler; +} + +void Scanner::clear_error() +{ + mb->clear_error(); +} + +void Scanner::runMessageLoop() +{ + FsmState *fsmState = FsmStateManagerEx::GetState(); + FsmState::setScanner(this); + do + { + ScanEvent evt = sysEvent.Take(); + fsmState = fsmState->on_event(evt); + } while (bMsgLoop); +} + +bool Scanner::paper_ready() +{ + return mb->paper_ready(); +} + +bool Scanner::get_keeplastpaper() +{ + return mb->get_keeplastpaper(); +} + +void Scanner::testRunscan() +{ + for (;;) + { + if (done_scan) + break; + FPGAConfigParam fpgaparam = GetFpgaparam(m_config.g200params.dpi, m_config.g200params.color); + capturer->open(m_config,fpgaparam); + int ch = 0; + int ixx = 0; + + // std::cout << "mod1:" << CV_8UC3 << " " << CV_8UC1 << std::endl; + StopWatch sw; + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + for (int i = 0; i < 150; i++) + { + capturer->snap(); + std::random_device rd; // obtain a random number from hardware + std::mt19937 gen(rd()); // seed the generator + std::uniform_int_distribution<> distr(150, 300); // define the range + std::this_thread::sleep_for(std::chrono::milliseconds(distr(gen))); + int channel = capturer->color() == 16 ? 3 : 1; + int dstwith = capturer->width() * 2 * 3 * channel; + // int dstHeight = m_config.g200params.paper == (unsigned int)PaperSize::G400_AUTO ? height : height / channel; + int dstHeight = capturer->getautosizeheight(); + static int scannum = 0; + void *data; + if (data = capturer->readFrame(5000)) + { + printf("\n+++++ readFrame:%fms+++++++++++\n", sw.elapsed_ms()); + if (imagehandler) + { + imagehandler->add_image(data, dstwith, dstHeight, capturer->color(), scannum,mfpgaversion); + } + } + else + { + printf("\n+++++ error readFrame:%fms+++++++++++\n", sw.elapsed_ms()); + } + } + capturer->close(); + } + imagehandler->add_scanevent({.From = STOPSCAN, 0}); +} -static int pickpapernum = 0; void Scanner::runScan() { - pickpapernum = 0; // system("sudo cpufreq-set -g performance"); system("echo performance > /sys/devices/system/cpu/cpu5/cpufreq/scaling_governor"); LOG_TRACE("+++++++scanner runinng+++++++++++++\n"); - mb->clear_error(); + + if(ExceptionCheck()) + { + printf("first page pick paper \n"); + startcapimage(true); + mb->pick_paper(); + { + done_scan = 0; + printf("set scancount %d\n", scancount); + mb->PutMsg(DisType::Dis_Scan, 0, ClearScreen::All); + mb->PutMsg(DisType::Dis_Scan_Page, mb->paper_counter(), ClearScreen::BOT); + + if (m_config.g200params.is_fixedpaper || m_config.g200params.paper != (uint)PaperSize::G400_AUTO) + fixedsizescan(); + else + autosizescan(); + savescannerinfo(scannerinfo); + while (!imagehandler->done()) + this_thread::sleep_for(chrono::milliseconds(10)); + done_scan = 0; + + if (wake.get()) + { + wake->resettime(); + wake->setsleepfalg(false); + } + system("sudo cpufreq-set -g ondemand"); + // system("sudo echo ondemand > /sys/devices/system/cpu/cpu5/cpufreq/scaling_governor"); + } + } + mb->SetKeyState(false); + m_capturereload.reset(new ThreadEx([&]{ + capturer->stop(); + capturer->close(); + capturer->reset(); })); + if ((((mb_error_code != 0) && (mb_error_code != 0xffffffff)) || imagehandler->getimgstatus().status != NO_error) && m_config.g200params.is_autopaper) + mb->set_auto_paper(false, false); + mb->startcapimage(false); + imagehandler->add_scanevent({.From = STOPSCAN, 0}); + ControlFeedMode(); + printf("-------scanner done-------\n"); +} + +bool Scanner::ExceptionCheck() +{ + bool ret = true; unsigned int val; - mb->set_double_inpect(m_config.g200params.double_feed_enbale); - mb->set_staple_inpect(m_config.g200params.stable_enbale); - // mb->set_paper_inspect(m_config.g200params.enable_sizecheck); - mb->set_auto_paper(m_config.g200params.is_autopaper);//m_config.g200params.is_autopaper - mb->set_screw_inpect(m_config.g200params.screw_detect_enable); - mb->set_screw_level(m_config.g200params.screw_detect_level); - mb->set_long_paper(m_config.g200params.paper); - //mb->set_cuospeed(41); - mb->start(); + mb->start(m_config); mb->read(0x01, val); if ((val & 0x700fe) > 0) { + ret = false; if ((val & 0x700fe) == 0x14) { imagehandler->add_scanevent({.From = MtBoard, .Code = 4}); LOG_TRACE("\nCover Open status"); imagehandler->add_scanevent({.From = STOPSCAN, 0}); - if (mb_error_code != 0 && m_config.g200params.is_autopaper) - mb->set_auto_paper(false); - return; } imagehandler->add_scanevent({.From = MtBoard, .Code = val & 0x700fe}); + if (m_config.g200params.is_autopaper) + { + imagehandler->add_scanevent({.From = STOPSCAN, 1}); + mb->set_auto_paper(false, false); + } + mb->errormsg(val & 0x1c003fa); printf("\n scan stop code =%d ", val & 0x700fe); } + +#ifdef G200 + StopWatch top_wh; + while (top_wh.elapsed_s() < 10) + { + if (is_ml_top || mb_error_code || handstop) + break; + this_thread::sleep_for(chrono::milliseconds(1)); + } + if (!is_ml_top || mb_error_code || handstop) + { + ret = false; + if (mb_error_code == 0 && handstop == 0) // 无其他异常时,发送升降台未到达指定位置异常 + { + imagehandler->add_scanevent({.From = MtBoard, 0x80000}); + if (m_config.g200params.is_autopaper) + mb->set_auto_paper(false, false); + } + if (mb_error_code && m_config.g200params.is_autopaper) + mb->set_auto_paper(false, false); + this_thread::sleep_for(chrono::milliseconds(20)); + imagehandler->add_scanevent({.From = STOPSCAN, 0}); + if (wake.get()) + { + wake->resettime(); + wake->setsleepfalg(false); + } + } + LOG_TRACE(string_format("waiting paper wait_arrival_top time = %0.2f ", top_wh.elapsed_ms())); +#endif + return ret; +} + +void Scanner::ControlFeedMode(){ + MotorboardParam::MBParam mbparam_tmp = MotorboardParam().GetParam(); + if (mbparam_tmp.automaticcontrolfeedmode) + { + printf("\n+++++++++ automaticcontrolfeedmode "); + MotorSessionInfo::MBTaskRecordInfo info_tmp{0}; + if (mb_error_code == 0) + info_tmp.NormalDone = true; + if (mb_error_code == 0x8) + info_tmp.FeedError = true; + if (mb_error_code == 0x10) + info_tmp.Jammed = true; + if (mb_error_code == 0x20) + info_tmp.DoubleFeed = true; + info_tmp.CurrentScaned = scannum; + FeedControl feedcontrol_tmp; + feedcontrol_tmp.AppendPattern(info_tmp); + switch (feedcontrol_tmp.GetPredictFeedMode()) + { + case FeedControl::FeedMode::FMode_Low: + setfeedmode(0); + break; + case FeedControl::FeedMode::FMode_Mid: + setfeedmode(1); + break; + case FeedControl::FeedMode::FMode_High: + setfeedmode(2); + break; + } + } +} + +bool Scanner::pickpaper() +{ + if (done_scan) + return false; + if (imagehandler) + { + while (imagehandler->is_limit()) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + // unsigned int reg2v; + // mb->read(0x02, reg2v); + // if (reg2v & 0x00010000) + // { //有纸 + printf("\n+++++++++pick paper "); + mb->pick_paper(); + startcapimage(true); + return true; + // } + // else + // { + // printf("\n+++++++++pick paper no paper"); + // return false; + // } +} + +void Scanner::set_motorboardcallback(MotorBoardGlue glue) +{ + mb->set_callbacks(glue); +} + +void Scanner::set_imgprocparams(HGImgProcParms params) +{ + imagehandler->config_procparams(params); +} + +void Scanner::test_cap(HGScanConfig config) +{ + printf("capturer openning \n"); + FPGAConfigParam fpgaparam = GetFpgaparam(m_config.g200params.dpi, m_config.g200params.color); + capturer->open(config,fpgaparam); + capturer->snap(); + void *data; + if (data = capturer->readFrame(2000)) + { + int imtype = capturer->color() ? CV_8UC3 : CV_8UC1; + cv::Mat mat; + cv::Mat saveMat; + std::vector ch_mats; + int dstwidth, dstheight; + int width = capturer->width(); + int height = capturer->height(); + dstwidth = width * 3; + dstheight = height / 3; + + if (imtype == CV_8UC3) + { + mat = cv::Mat(height / 3, width * 9, CV_8UC1, data); + saveMat = cv::Mat(dstheight, dstwidth, CV_8UC3); + } + + else + { // gray + saveMat = cv::Mat(height, width * 3, CV_8UC1, data); + } + static int savenum; + if (imtype == CV_8UC3) + { + for (int i = 0; i < 3; i++) + { // B G R + cv::Mat mattemp = mat(cv::Rect(dstwidth * i, 0, dstwidth, dstheight)); + ch_mats.push_back(mattemp); + } + swap(ch_mats[1], ch_mats[2]); + cv::merge(ch_mats, saveMat); + } + cv::imwrite(std::to_string(++savenum) + ".jpg", saveMat); + } else { -#ifdef G200 - if ((int)m_mbver > 0) - { - StopWatch top_wh; - while (top_wh.elapsed_s() < 10) - { - if (is_ml_top || mb_error_code || handstop) - break; - this_thread::sleep_for(chrono::milliseconds(1)); - } - if (!is_ml_top || mb_error_code || handstop) - { - if (mb_error_code == 0 && handstop == 0) // 无其他异常时,发送升降台未到达指定位置异常 - imagehandler->add_scanevent({.From = MtBoard, 0x80000}); - capturer->reset(); - this_thread::sleep_for(chrono::milliseconds(20)); - imagehandler->add_scanevent({.From = STOPSCAN, 0}); - return; - } - } - else - this_thread::sleep_for(chrono::milliseconds(2500)); -#endif - done_scan = 0; - if((int)m_mbver > 1) - scanpaperout(); - else - scanold(); + printf("LOST Image \n"); } - this_thread::sleep_for(chrono::milliseconds(1000)); + capturer->close(); + printf("capturer closed \n"); +} +void Scanner::set_sleeptime(int val) +{ + if (wake.get()) + wake->settime(val); +} + +int Scanner::get_sleeptime() +{ + if (wake.get()) + return wake->gettime(); + return 0; +} + +void Scanner::resettime() +{ + if (wake.get()) + wake->resettime(); +} + +int Scanner::get_sleepstatus() +{ + if (wake.get()) + return wake->get_status(); + return 0; +} + +void Scanner::set_paprent(void *parent) +{ + if (parent) + m_parent = parent; +} + +void Scanner::settrayposition(int value) +{ + printf("\n Scanner settrayposition %d", value); + if (mb.get()) + { + uint val = 0; + mb->read(6, val); + auto tmp = *(SMB_FUNC *)&val; + tmp.param.lift_init_set = value; + mb->write(6, tmp.value); + printf("\n Scanner settrayposition mbvalue %d", tmp.value); + MotorboardParam().GetOrSetTrayPosition(false, value); + } +} + +void Scanner::setfeedmode(int value) +{ + printf("\n Scanner setfeedmode %d", value); + if (mb.get()) + { + uint val = 0; + mb->read(6, val); + auto tmp = *(SMB_FUNC *)&val; + switch (value) + { + case 0: + tmp.param.func_feed_low = 1; + tmp.param.func_feed_high = tmp.param.func_feed_mid = 0; + break; + case 1: + tmp.param.func_feed_mid = 1; + tmp.param.func_feed_high = tmp.param.func_feed_low = 0; + break; + case 2: + tmp.param.func_feed_high = 1; + tmp.param.func_feed_mid = tmp.param.func_feed_low = 0; + break; + default: + tmp.param.func_feed_mid = 1; + tmp.param.func_feed_high = tmp.param.func_feed_low = 0; + break; + } + mb->write(6, tmp.value); + printf("\n Scanner setfeedmode mbvalue %d", tmp.value); + MotorboardParam().GetOrSetFeedMode(false, value); + } +} +void Scanner::set_sleepstatus(bool off) +{ if (wake.get()) { - wake->resettime(); - wake->setsleepfalg(false); + if (off) + wake->power_on(); + else + wake->power_off(); } - imagehandler->add_scanevent({.From = STOPSCAN, 0}); - capturer->reset(); - if (mb_error_code != 0 && m_config.g200params.is_autopaper) - mb->set_auto_paper(false); - printf("\n-------scanner done-------\n"); } bool Scanner::getpaperon() { -#ifdef G200 + //#ifdef G200 if (mb.get()) { uint val = 0; mb->read(2, val); + if ((val & 0x10000) && m_config.g200params.is_autopaper) + mb->set_auto_paper(false, false); return val & 0x10000; } return 0; -#endif - return 1; + // #endif + // return 1; } -void Scanner::scanpaperout() -{ - StopWatch sw; - StopWatch swCap; - void *data = NULL; - int scannum = 0; - startcapimage(); - printf("first page pick paper \n"); +void Scanner::autosizescan() +{ + void *data = NULL; + scannum = 0; + StopWatch sw, swCap; for (;;) { LOG_TRACE("waiting paper"); - - if (!done_scan) // + if (!done_scan) //&& mb->wait_paper_in(10000) { - //LOG_TRACE(string_format("+++++paper on:%fms+++++++++++ ", swCap.elapsed_ms())); - if (mb->wait_paper_out(3000)) + printf("waiting paper"); + if (int ret = waitpaperout()) { - printf("wait_paper_out time =%f \n",sw.elapsed_ms()); - sw.reset(); - swCap.reset(); - if (data = capturer->readFrame(2000)) + printf("\n waitpaperout %d ", ret); { - printf("\n readFrame time =%f pickpapernum = %d",swCap.elapsed_ms(),pickpapernum++); - if (imagehandler) + if ((scancount <= (++scannum))) { - imagehandler->add_image(data, capturer->width(), capturer->height() / 3 * 3, capturer->color(), scannum++,0x90001,CISVendor::DUNNAN_CIS_V0); - data = NULL; + done_scan = 1; + mb->stop(); + } + if (mb_error_code != 0) + { + printf("\n wait paperout mb_error_code break"); + if (!(m_cap.isuploadexceptionimage && (mb_error_code & 0x20) == 0x20)) + break; + else + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + } + if (ret == 3) + { + done_scan = true; + printf("\n wait paperout return 3 break"); + break; } - swCap.reset(); scannerinfo.RollerNum++; - LOG_TRACE(string_format("capture one=%fms", swCap.elapsed_ms())); + scannerinfo.TotalScanned++; + if (ret == 2) + { + mb->stop(); + done_scan = true; + imagehandler->add_scanevent({.From = MtBoard, .Code = 0x10000}); + this_thread::sleep_for(chrono::milliseconds(100)); + imagehandler->add_scanevent({.From = MtBoard, .Code = 0x40000}); + printf("\n paper with Hole stop "); + } + if (getcapimageflag()) + { + mb->stop(); + done_scan = true; + imagehandler->add_scanevent({.From = MtBoard, .Code = 0x10000}); + this_thread::sleep_for(chrono::milliseconds(100)); + imagehandler->add_scanevent({.From = MtBoard, .Code = 0x40000}); + break; + } + } + uint height = 0; + if (m_config.g200params.paper == (unsigned int)PaperSize::G400_AUTO) + { + capturer->regs()->read(0x14,height); + if(height < 1000 ) + std::this_thread::sleep_for(std::chrono::milliseconds((1000 - height)/70)); + int delaytime = m_config.g200params.dpi == 0x02 ? 100 : (m_config.g200params.dpi == 0x03 ? 250 : 30); + this_thread::sleep_for(chrono::milliseconds(delaytime)); //纸张过了 多采集几张 + height = capturer->getautosizeheight(); } else { - imagehandler->add_scanevent({.From = V4L2, .Code = 0}); - // LOG_TRACE("capture error"); - // done_scan = 1; - // capturer->stop(); - // mb->stop(); - LOG_TRACE("capture error Stop Scan"); - break; +#ifdef G200 + int delaytime = m_config.g200params.dpi == 0x02 ? 60 : (m_config.g200params.dpi == 0x03 ? 170 : 27); +#else + int delaytime = m_config.g200params.dpi == 0x02 ? 100 : (m_config.g200params.dpi == 0x03 ? 250 : 50); +#endif + this_thread::sleep_for(chrono::milliseconds(delaytime)); //纸张过了 多采集几张 + height = capturer->getautosizeheight(); + } + if (height) + { + if (!(m_cap.is_dogeardetection || m_cap.en_sizecheck)) + { + if (!pickpaper()) + done_scan = 1; + } + int channel = capturer->color() == 16 ? 3 : 1; + int dstwith = capturer->width() * 2 * 3 * channel; + // int dstHeight = m_config.g200params.paper == (unsigned int)PaperSize::G400_AUTO ? height : height / channel; + int dstHeight = height; + printf("\ndstwith =%d dstHeight = %d scancount %d", dstwith, dstHeight, scannum); + swCap.reset(); + if (data = capturer->readFrame(10000)) + { + printf("\n+++++ readFrame:%fms+++++++++++\n", sw.elapsed_ms()); + if (imagehandler) + { + imagehandler->add_image(data, dstwith, dstHeight, capturer->color(), scannum,mfpgaversion); + data = NULL; + } + if (m_cap.is_dogeardetection || m_cap.en_sizecheck) + { + if (imagehandler->getimgstatus().status != NO_error) + { + printf("\n+++++ status :%d ms+++++++++++\n", imagehandler->getimgstatus().status); + mb->stop(); + done_scan = 1; + switch (imagehandler->getimgstatus().status) + { + case Error_Status::Dog_error: + mb->PutMsg(DisType::Dis_Err_DogEar, 0, ClearScreen::All); + break; + case Error_Status::Size_error: + mb->PutMsg(DisType::Dis_Err_Size, 0, ClearScreen::All); + break; + default: + break; + } + } + else + { + if (!pickpaper()) + done_scan = 1; + } + } + printf("\n+++++ addimage:%fms+++++++++++\n", sw.elapsed_ms()); + LOG_TRACE(string_format("capture one=%fms", swCap.elapsed_ms())); + } + else + { + imagehandler->add_scanevent({.From = V4L2, .Code = 0}); + done_scan = true; + LOG_TRACE("capture error"); + printf("capture error \n"); + } } } else @@ -359,10 +1018,138 @@ void Scanner::scanpaperout() { uint value = 0; mb->read(0x2, value); - if (!(value & 0x20000))//bit 17 scandone + if (!(value & 0x20000)) // bit 17 scandone { + printf("mb 02 reg value =%d \n", value); done_scan = 1; LOG_TRACE("---------Time out-----"); + break; + } + else + { + mb->stop(); + done_scan = true; + imagehandler->add_scanevent({.From = MtBoard, .Code = 0x10000}); + printf("\n time out "); + break; + } + } + } + } + else + { + printf("\n done scan break"); + break; + } + } +} + +void Scanner::fixedsizescan() +{ + void *data = NULL; + scannum = 0; + StopWatch sw; + StopWatch swCap; + for (;;) + { + LOG_TRACE("waiting paper"); + if (!done_scan) //&& mb->wait_paper_in(10000) + { + // capturer->snap(); + printf("waiting paper...\n"); + int timedelay = m_config.g200params.dpi == 0x02 ? 25 : (m_config.g200params.dpi == 0x03 ? 35 : 15); + this_thread::sleep_for(chrono::milliseconds(timedelay)); //纸张过了 多采集几张 + if (mb->wait_paper_out(10000)) + { + if ((scancount <= (++scannum))) + { + done_scan = 1; + mb->stop(); + } + if (mb_error_code != 0) + { + printf("\n +++++ mb_error_code =%d ++++++", mb_error_code); + if (!(m_cap.isuploadexceptionimage && (mb_error_code & 0x20) == 0x20)) + break; + } + uint height; + if (m_config.g200params.paper == (unsigned int)PaperSize::G400_AUTO) + { + capturer->regs()->read(0x14,height); + if(height < 1000 ) + std::this_thread::sleep_for(std::chrono::milliseconds((1000 - height)/70)); + int delaytime = m_config.g200params.dpi == 0x02 ? 100 : (m_config.g200params.dpi == 0x03 ? 250 : 50); + this_thread::sleep_for(chrono::milliseconds(delaytime)); //纸张过了 多采集几张 + height = capturer->getautosizeheight(); + printf("\n+++++ getautosizeheights+++++++++++\n"); + } + else + { + height = capturer->height(); + printf("\n+++++ height+++++++++++\n"); + } + if (height) + { + int channel = capturer->color() == 16 ? 3 : 1; + int dstwith = capturer->width() * 2 * 3 * channel; + int dstHeight = m_config.g200params.paper == (unsigned int)PaperSize::G400_AUTO ? height : height / channel; + // int dstHeight = height; + printf("\ndstwith =%d dstHeight = %d scancount %d", dstwith, dstHeight, scannum); + if (data = capturer->readFrame(10000)) + { + printf("\n+++++ readFrame:%fms+++++++++++\n", sw.elapsed_ms()); + if (imagehandler) + { + imagehandler->add_image(data, dstwith, dstHeight, capturer->color(), scannum,mfpgaversion); + data = NULL; + } + if (imagehandler->getimgstatus().status != NO_error) + { + printf("\n+++++ status :%d ms+++++++++++\n", imagehandler->getimgstatus().status); + mb->stop(); + done_scan = 1; + switch (imagehandler->getimgstatus().status) + { + case Error_Status::Dog_error: + mb->PutMsg(DisType::Dis_Err_DogEar, 0, ClearScreen::All); + break; + case Error_Status::Size_error: + mb->PutMsg(DisType::Dis_Err_Size, 0, ClearScreen::All); + break; + default: + break; + } + } + else + { + if (!pickpaper()) + done_scan = 1; + } + printf("\n+++++ addimage:%fms+++++++++++\n", sw.elapsed_ms()); + scannerinfo.RollerNum++; + scannerinfo.TotalScanned++; + } + else + { + imagehandler->add_scanevent({.From = V4L2, .Code = 0}); + done_scan = true; + LOG_TRACE("capture error"); + printf("capture error \n"); + } + } + } + else + { + if (!done_scan) + { + uint value = 0; + mb->read(0x2, value); + if (!(value & 0x20000)) // bit 17 scandone + { + printf("mb 02 reg value =%d \n", value); + done_scan = 1; + LOG_TRACE("---------Time out-----"); + break; } } } @@ -371,133 +1158,31 @@ void Scanner::scanpaperout() { break; } - if (imagehandler->getimgstatus().status != NO_error) - { - mb->stop(); - done_scan = 1; - capturer->stop(); - LOG_TRACE("imagehandler->getimgstatus().dogear_error "); - break; - } - if ((scancount <= scannum)) - { - done_scan = 1; - capturer->stop(); - this_thread::sleep_for(chrono::milliseconds(2000)); - mb->stop(); - break; - } - if (m_cap.resolution_dst >= 400 && papersMap[(PaperSize)m_config.g200params.paper].height <= 8100) - this_thread::sleep_for(chrono::milliseconds(3000)); - else if (m_cap.resolution_dst >= 400 && (papersMap[(PaperSize)m_config.g200params.paper].height > 8100 && papersMap[(PaperSize)m_config.g200params.paper].height <= 10800)) - this_thread::sleep_for(chrono::milliseconds(5000)); - else if (m_cap.resolution_dst >= 400 && papersMap[(PaperSize)m_config.g200params.paper].height > 10800) - this_thread::sleep_for(chrono::milliseconds(8000)); - startcapimage(); - mb->pick_paper(); - printf(" pick_paper time =%f \n", swCap.elapsed_ms()); - LOG_TRACE("pick_paper"); } - savescannerinfo(scannerinfo); - while (!imagehandler->done()) - this_thread::sleep_for(chrono::milliseconds(10)); - capturer->close(); - done_scan = 0; - system("sudo cpufreq-set -g ondemand"); - // system("sudo echo ondemand > /sys/devices/system/cpu/cpu5/cpufreq/scaling_governor"); - LOG_TRACE("-------scanner done-------\n"); } -void Scanner::scanold() +void Scanner::clean_paper_road() { - StopWatch sw; - StopWatch swCap; - void *data = NULL; - int scannum = 0; - for (;;) - { - LOG_TRACE("waiting paper"); - sw.reset(); - if (!done_scan && mb->wait_paper_in(1000)) - { - printf("wait_paper_in time =%f \n",swCap.elapsed_ms()); - //testGpio->setValue(Gpio::High); - LOG_TRACE(string_format("+++++paper on:%fms+++++++++++ ", swCap.elapsed_ms())); - capturer->snap(); - //testGpio->setValue(Gpio::Low); - swCap.reset(); - if (data = capturer->readFrame(2000)) - { - printf("readFrame time =%f \n",swCap.elapsed_ms()); - swCap.reset(); - if (imagehandler) - { - imagehandler->add_image(data, capturer->width(), capturer->height() / 3 * 3, capturer->color(), scannum++,0x90001,CISVendor::DUNNAN_CIS_V0); - data = NULL; - } - LOG_TRACE(string_format("readFrame time =%f ",swCap.elapsed_ms())); - printf("addimage time =%f \n",swCap.elapsed_ms()); - swCap.reset(); - scannerinfo.RollerNum++; - scannerinfo.TotalScanned++; - } - else - { - imagehandler->add_scanevent({.From = V4L2, .Code = 0}); - LOG_TRACE("capture error"); - } - swCap.reset(); - } - else if (done_scan) - { - break; - } - else - { - if (!done_scan) - { - uint value = 0; - mb->read(0x2, value); - if (!(value & 0x20000))//bit 17 scandone - { - printf("\n mb 02 reg value =%d ",value); - done_scan = 1; - LOG_TRACE("---------Time out-----"); - break; - } - } - } - if (imagehandler->getimgstatus().status != NO_error) - { - mb->stop(); - done_scan = 1; - capturer->stop(); - LOG_TRACE("imagehandler->getimgstatus().dogear_error "); - break; - } - if ((scancount <= scannum)) - { - done_scan = 1; - capturer->stop(); - this_thread::sleep_for(chrono::milliseconds(2000)); - mb->stop(); - break; - } - if(m_cap.resolution_dst>=400 && papersMap[(PaperSize)m_config.g200params.paper].height<=8100) - this_thread::sleep_for(chrono::milliseconds(3000)); - else if(m_cap.resolution_dst>=400 && (papersMap[(PaperSize)m_config.g200params.paper].height>8100&&papersMap[(PaperSize)m_config.g200params.paper].height<=10800)) - this_thread::sleep_for(chrono::milliseconds(5000)); - else if(m_cap.resolution_dst>=400 && papersMap[(PaperSize)m_config.g200params.paper].height>10800) - this_thread::sleep_for(chrono::milliseconds(8000)); - mb->pick_paper(); - swCap.reset(); - LOG_TRACE("pick_paper"); - } - savescannerinfo(scannerinfo); - while(!imagehandler->done()) - this_thread::sleep_for(chrono::milliseconds(10)); - capturer->close(); - done_scan = 0; - system("sudo cpufreq-set -g ondemand"); - //system("sudo echo ondemand > /sys/devices/system/cpu/cpu5/cpufreq/scaling_governor"); + if(mb.get()) + mb->clean_paper_road(); +} +int Scanner::waitpaperout() +{ + if (mb->wait_paper_out(10000)) //10秒内收到正常翻转信号或者异常时 返回 1 继续扫描 + return 1; + uint reg0,reg14; + reg0 = reg14 =0; + capturer->regs()->read(14, reg14); + capturer->regs()->read(0, reg0); + if(m_config.g200params.color) + reg14 *=3; + printf("\n wait paperout reg14 =%d reg0 =%d",reg14,reg0); + if ((reg14 & 0xffff) == 0) // 未收到异常与翻转信号 返回 0 退出扫描 + return 0; + // if(handstop && (capturer->regs()->read(14,val)&0xffff) > 0) + if (handstop) //pc手动停止时返回 3 退出扫描流程 不进行标位置回读和计数累加 + return 3; + if ((reg14 & 0xffff) == (reg0 & 0xffff)) + return mb_error_code == 0 ? 2 : 0; // 无异常有图像时 返回2 读取图像数据 防止丢图 + return 0; } \ No newline at end of file diff --git a/device/gxx-linux/scanner/scanner.h b/device/gxx-linux/scanner/scanner.h index 2afab49..6da31c1 100644 --- a/device/gxx-linux/scanner/scanner.h +++ b/device/gxx-linux/scanner/scanner.h @@ -1,31 +1,98 @@ #pragma once -#include "iscanner.h" +#include +#include +#include "BlockingQueue.h" +#include "fsmstate.h" +#include +#include "IScanner.h" +#include "wakeup.hpp" +#include "commondef.h" -enum MotorVersion : uint{ - Motor_old, - Motor_mltop, - Motor_paperout, -}; +class MotorBoard; +class ICapturer; +class IImageHandler; +class MotorController; +class CSizedetect; +class CImageApplyDogEarDetection; class Scanner : public IScanner { public: - Scanner(std::shared_ptr capturer, std::shared_ptr mb, std::shared_ptr wake); + Scanner(std::shared_ptr capturer, std::shared_ptr mb, std::shared_ptr wake); virtual ~Scanner(); + virtual void try_scan(const std::string encodehexstr) override; + virtual void configparam(HGScanConfig config) override; virtual void start_scan() override; virtual void stop_scan() override; - virtual int count() override; + + virtual int count() override; virtual int mode() override; - virtual int getmbstatus() override; - virtual bool getpaperon() override; - virtual void runScan() override; + virtual void put(ScanEvent evt) override { sysEvent.Put(evt); } + virtual bool is_runscan() override; + virtual void set_imagehandler(std::shared_ptr handler = nullptr) override; + virtual void clear_error() override; + virtual bool paper_ready() override; + virtual bool get_keeplastpaper() override; + virtual void set_motorboardcallback(MotorBoardGlue glue) override; + virtual void set_imgprocparams(HGImgProcParms parmas) override; + virtual void test_autocorrect(int colormode) override; + virtual void test_cap(HGScanConfig config) override; + virtual bool set_hgimgconfig(GScanCap config) override; + virtual void add_scansever(HGIntInfo event) override; + virtual void set_sleeptime(int val) override; + virtual int get_sleeptime() override; + virtual void resettime() override; + virtual int get_sleepstatus() override; + virtual void set_sleepstatus(bool off) override; + virtual int getimageprocedone() override; + virtual void set_paprent(void *parent) override; + virtual bool getpaperon() override; + virtual int getmbstatus() override; + virtual std::string getmbversion() override; + virtual void setfeedmode(int value) override; + virtual void settrayposition(int value) override; + virtual void clean_paper_road() override; private: - void scanold(); - void scanpaperout(); + void runMessageLoop(); + void runScan(); + void testRunscan(); + void preFeed(); + void startcapimage(bool value); + bool getcapimageflag(); + bool pickpaper(); + void autosizescan(); + void fixedsizescan(); + int waitpaperout(); + void ControlFeedMode(); + bool ExceptionCheck(); + ImgStatus ImgDetect(); + std::thread threadRunMessageLoop; + volatile bool bMsgLoop = true; + BlockingQueue sysEvent; + + std::shared_ptr m_dog; + std::shared_ptr m_sizedetect; + + std::shared_ptr mb; + std::shared_ptr capturer; + std::shared_ptr wake; + + std::shared_ptr fu_runscan; + std::shared_ptr imagehandler; + std::shared_ptr m_motorcontrol; + + std::shared_ptr m_capturereload; + std::function m_mtcallback; volatile int done_scan = 0; volatile bool is_ml_top = 0; volatile bool handstop = 0; - volatile int mb_error_code = 0; - MotorVersion m_mbver; - + volatile int scannum = 0; + int scancount = 0; + volatile unsigned int mb_error_code; + HGScanConfig m_config; + GScanCap m_cap; + ScannerNativeParam scannerinfo; + void *m_parent; + std::string mbversion; + unsigned int mfpgaversion; }; diff --git a/device/gxx-linux/scanner/scannero300.cpp b/device/gxx-linux/scanner/scannero300.cpp deleted file mode 100644 index e4849ee..0000000 --- a/device/gxx-linux/scanner/scannero300.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include -#include "Imotorboard.h" -#include "Capturer.h" -#include -#include "StopWatch.h" -#include "iimagehandler.h" -#include "applog.h" -#include "stringex.hpp" -#include "fpgacontrol.h" -#include "scannerregs.h" -#include "fpgacontrol.h" -#include "Gpio.h" -#include "scannero300.h" -#include "SysInforTool.h" -#include "correct_ultis.h" -#include "dailex.hpp" -static const std::string loggername = "ScannerO300"; -ScannerO300::ScannerO300(std::shared_ptr capturer, std::shared_ptr mb, std::shared_ptr wake) : IScanner(capturer, mb, wake), mfpgaversion(0x90001) -{ - LOG_INIT(); - capturer->regs()->read(15, mfpgaversion); - SysInforTool(ScannerSysInfo()).GetSysInfo(); - auto mb_error_call = [&](std::uint32_t code) - { - if (done_scan) - return; - if (code == 0x40000 && m_config.g200params.paper != 16) - return; - if (code != 0) - { - imagehandler->add_scanevent({.From = MtBoard, .Code = code}); - mb_error = code; - if (code == 0x20) - scannerinfo.DoubleFeedTimes++; - done_scan = true; - } - printf("\n scan done 1 code = %d ", code); - }; - auto mb_scandone_call = [&]() - { - printf("\n scan done 2"); - done_scan = true; - }; - - auto mb_auto_paper = [&](unsigned int value) - { - printf("连续扫描模式检测到有纸"); - if (fu_runscan && fu_runscan->is_runing()) - return; - start_scan(); - }; - mb->set_callbacks({mb_error_call, mb_scandone_call, nullptr, nullptr, nullptr, mb_auto_paper}); - scannerinfo = getscannerinfo(); - - auto mb_ev_cb = [&](uint32_t ev) -> void - { - if(imagehandler) - imagehandler->add_scanevent({.From = MBEvent, .Code = ev}); - }; - mb->set_motorboard_event_callback(mb_ev_cb); -} -ScannerO300::~ScannerO300() -{ -} -void ScannerO300::start_scan() -{ - printf("m_config.g200params.color= %d ,m_config.g200params.dpi = %d ,m_config.g200params.paper = %d ", m_config.g200params.color, m_config.g200params.dpi, m_config.g200params.paper); - mb->clear_error(); - capturer->regs()->read(15, mfpgaversion); - if (m_capturereload && m_capturereload->is_runing()) - { - while (m_capturereload->is_runing()) - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - m_capturereload.reset(); - } - if (fu_runscan && fu_runscan->is_runing()) - return; - if (wake.get()) - wake->setsleepfalg(true); - m_cistype = Dail().GetValue().dails.in_voltage3 == 1 ? CISVendor::DUNNAN_CIS_V0 : CISVendor::HUALIN_CIS_V0; - FPGAConfigParam fpgaparam = GetFpgaparam(m_config.g200params.dpi, m_config.g200params.color); - capturer->open(m_config, fpgaparam); - scannerinfo = getscannerinfo(); - imagehandler->Set_ratio(fpgaparam.HRatio, fpgaparam.VRatio); - imagehandler->resetimgstatus(); - mb->clear_error(); - mb_error = 0; - scancount = 0; - fu_runscan.reset(new ThreadEx(&ScannerO300::runScan, this)); -} -void ScannerO300::stop_scan() -{ - done_scan = true; - mb->set_auto_paper(false); -} -int ScannerO300::count() -{ - return scannerinfo.RollerNum; -} -int ScannerO300::mode() -{ - return 0; -} -int ScannerO300::getmbstatus() -{ - return 0; -} -bool ScannerO300::getpaperon() -{ - return mb->paper_ready(); -} -void ScannerO300::runScan() -{ - int spdmode = 0; - if (scannerSp.find((SpeedMode)scannerinfo.speedmode) != scannerSp.end()) - spdmode = scannerSp.at((SpeedMode)scannerinfo.speedmode).motorSpeed; - mb->set_speed_mode(spdmode, m_config.g200params.dpi, m_config.g200params.color); - system("echo performance > /sys/devices/system/cpu/cpu5/cpufreq/scaling_governor"); - mb->set_double_inpect(m_config.g200params.double_feed_enbale); - mb->set_auto_paper(m_config.g200params.is_autopaper); - - StopWatch sw; - if (mb->is_converopen()) - { - imagehandler->add_scanevent({.From = MtBoard, .Code = 4}); - mb_error = 4; - printf("\n------------------converopen-------------------"); - } - else if (mb->is_jam()) - { - imagehandler->add_scanevent({.From = MtBoard, .Code = 16}); - mb_error = 16; - printf("\n------------------jam-------------------"); - } - else if (!mb->paper_ready()) - { - imagehandler->add_scanevent({.From = MtBoard, .Code = 2}); - mb_error = 2; - printf("\n-------------------no paper---------------"); - } - else - { - done_scan = false; - printf("\n------------------motor run ------------------- %f ", sw.elapsed_ms()); - std::thread m_startthread([this, spdmode] - { - std::this_thread::sleep_for(std::chrono::milliseconds(20));//20ms再启动 保证到达 wait paper in 之后才有传感器信号 - mb->set_cuospeed(0xff,m_config.g200params.dpi,m_config.g200params.color); - mb->start(); - std::this_thread::sleep_for(std::chrono::milliseconds(90)); - mb->stop_pick_paper(); - mb->set_cuospeed(spdmode,m_config.g200params.dpi,m_config.g200params.color); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - mb->pick_paper(); }); - void *data = NULL; - while (!done_scan) - { - if (mb->wait_paper_in(5000)) - { - printf("\n------------------wait_paper_in------------------- %f ", sw.elapsed_ms()); - if (mb_error != 0) - break; - capturer->snap(); - if (mb->wait_paper_out(7000)) - { - printf("\n------------------wait_paper_out------------------- %f ", sw.elapsed_ms()); - if (mb_error != 0) - break; - scannerinfo.RollerNum++; - scannerinfo.TotalScanned++; -#ifdef G300 - HGSize size; - size = papersMap[(PaperSize)m_config.g200params.paper]; - size.width = size.width == 0 ? papersMap[PaperSize::G400_A4].width : size.width; - size.height = size.height == 0 ? papersMap[PaperSize::G400_A4].height : size.height; - if (m_config.g200params.dpi != 1) - size.height = std::min((unsigned int)16002, size.height * 3 / 2); - int channels = m_config.g200params.color ? 3 : 1; - int dstwith = size.width * channels * 3; - int dstHeight = size.height / 9 * 3; -#else - int height; // - if (m_config.g200params.paper == (unsigned int)PaperSize::G400_AUTO) - { - int delaytime = m_config.g200params.dpi == 0x02 ? 150 : (m_config.g200params.dpi == 0x03 ? 250 : 100); - this_thread::sleep_for(chrono::milliseconds(delaytime)); // 纸张过了 多采集几张 - height = capturer->getautosizeheight(); - } - else - height = capturer->height(); - int channel = capturer->color() == 16 ? 3 : 1; - int dstwith = capturer->width() * 2 * 3 * channel; - int dstHeight = m_config.g200params.paper == (unsigned int)PaperSize::G400_AUTO ? height : height / channel; -#endif - printf("\n------------------readFrame------------------- %f", sw.elapsed_ms()); - if (data = capturer->readFrame(7000)) - { - printf("\n addimage %f ", sw.elapsed_ms()); - while (imagehandler->is_limit()) - { - this_thread::sleep_for(chrono::milliseconds(10)); - continue; - } - printf("\n dstwith = %d ,dstHeight = %d color type = %d", dstwith, dstHeight, capturer->color()); - imagehandler->add_image(data, dstwith, dstHeight, capturer->color(), ++scancount, mfpgaversion, m_cistype); - } - else - { - imagehandler->add_scanevent({.From = V4L2, .Code = 0}); - done_scan = true; - mb_error = 79; // 79异常取图失败 - printf("capture error \n"); - break; - } - if (imagehandler->getimgstatus().status != Error_Status::NO_error && (m_cap.is_dogeardetection || m_cap.en_sizecheck)) - { - done_scan = true; - mb_error = 82; - break; - } - if ((!mb->paper_ready()) || (scancount >= (m_cap.is_duplex ? m_cap.scannum / 2 : m_cap.scannum))) - { - done_scan = true; - break; - } - printf("\n scancount =%d m_cap.scannum =%d addimage %f", scancount, m_cap.scannum, sw.elapsed_ms()); - if (!done_scan) - mb->pick_paper(); - else - { - done_scan = true; - break; - } - printf("\n pick paper done %f ", sw.elapsed_ms()); - } - else - { - printf("\n scan done 16"); - if (mb_error == 0) - { - scannerinfo.JamTimes++; - imagehandler->add_scanevent({.From = MtBoard, .Code = 16}); - mb_error = 16; - } - break; - } - } - else - { - printf("\n scan done 8"); - imagehandler->add_scanevent({.From = MtBoard, .Code = 8}); - mb_error = 8; - scannerinfo.FeedErrorTimes++; - break; - } - } - printf("\n scan done 5"); - if (m_startthread.joinable()) - m_startthread.join(); - if ((mb_error == 0) || (mb_error == 82)) - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - mb->stop(); - } - mb->set_double_inpect(false); - m_capturereload.reset(new ThreadEx([&] - { - capturer->stop(); - capturer->close(); - capturer->reset(); })); - while (!imagehandler->done()) - this_thread::sleep_for(chrono::milliseconds(10)); - printf("-------scanner done------- %f \n", sw.elapsed_ms()); - imagehandler->add_scanevent({.From = STOPSCAN, 0}); - system("sudo cpufreq-set -g ondemand"); - if (wake.get()) - { - wake->resettime(); - wake->setsleepfalg(false); - } - savescannerinfo(scannerinfo); - done_scan = true; - if (mb_error && mb_error != 2) - { - mb->LedControlOption(HG_LedOption::HG_RED_ON, 0); - } - if (mb_error) - { - mb->set_auto_paper(false); - } - mb->set_error(mb_error); - if (!mb->paper_ready() && (mb_error == 0 || (mb->is_converopen() == false && mb->is_jam() == false && mb_error != 2))) - mb->motor_reset(); -} \ No newline at end of file diff --git a/device/gxx-linux/scanner/scannero300.h b/device/gxx-linux/scanner/scannero300.h deleted file mode 100644 index 62a2615..0000000 --- a/device/gxx-linux/scanner/scannero300.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "iscanner.h" - - -class ScannerO300 : public IScanner -{ -public: - ScannerO300(std::shared_ptr capturer, std::shared_ptr mb, std::shared_ptr wake); - virtual ~ScannerO300(); - virtual void start_scan() override; - virtual void stop_scan() override; - virtual int count() override; - virtual int mode() override; - virtual int getmbstatus() override; - virtual bool getpaperon() override; - virtual void runScan() override; -private: - volatile bool done_scan = true; - volatile int mb_error = 0; - std::uint32_t mfpgaversion; - CISVendor m_cistype; - //std::future m_addimg_future; -}; \ No newline at end of file diff --git a/device/gxx-linux/scanner/scannerregs.cpp b/device/gxx-linux/scanner/scannerregs.cpp index 0c813d8..1abe04b 100644 --- a/device/gxx-linux/scanner/scannerregs.cpp +++ b/device/gxx-linux/scanner/scannerregs.cpp @@ -1,7 +1,9 @@ #include "scannerregs.h" #include #include -#include "iscanner.h" +#include +#include "IScanner.h" +#include "scanner.h" #include "usbimageprocqueue.h" #include "filetools.h" #include "stringex.hpp" @@ -10,11 +12,10 @@ #include "memoryex.h" #include "jsonconfig.h" #include "CorrectParam.h" +#include "MotorboardParam.h" #include "hgutils.h" -#include "MotorConfig.h" -#include "dailex.hpp" -#include "deviceconfig.h" #include "base64.hpp" +#include "deviceconfig.h" unsigned long getfilesize(const char *filename) { @@ -89,6 +90,7 @@ ScannerRegAccess::ScannerRegAccess(std::shared_ptr scanner, std::share this->m_upstautus = Start_updata; this->scanner->set_paprent(this); file_pos = 0; + m_token = "null"; } ScannerRegAccess::~ScannerRegAccess() @@ -144,10 +146,6 @@ bool ScannerRegAccess::write(unsigned int addr, const unsigned int val) return true; case SR_IM_TYPE: return true; - case SR_NOTIFY_SLEEP: - if(scanner->get_sleepstatus() == 0) - scanner->set_sleepstatus(true); - return true; case SR_IM_TX: { // if (val != 1 && (transmit->is_writing() || usbimages->empty())) @@ -166,11 +164,24 @@ bool ScannerRegAccess::write(unsigned int addr, const unsigned int val) } return true; } + case SR_NOTIFY_SLEEP: + if(scanner->get_sleepstatus() == 0) + scanner->set_sleepstatus(true); + return true; + case SR_SET_FEEDMODE: + if(val <3 && val >=0) + scanner->setfeedmode(val); + return true; + case SR_SET_TRAYPOSITION: + if(val <3 && val >=0) + scanner->settrayposition(val); + return true; case SR_IM_POP: usbimages->pop(); return true; case SR_IM_ABORT: transmit->cannel(); + printf("\n SR_IM_ABORT "); return true; case SR_CONFIG_SCAN_PARAM: scanner->configparam(*((HGScanConfig *)&val)); @@ -191,6 +202,8 @@ bool ScannerRegAccess::write(unsigned int addr, const unsigned int val) cap.resolution_dst = scan_dpi; cap.resolution_native = 200; cap.scannum = scan_cnt; + cap.pixtype = 0; + usbimages->set_dpi(scan_dpi, scan_dpi); printf("DPI: %d, Count: %d\n", scan_dpi, scan_cnt); #else std::vector data(val); @@ -277,7 +290,7 @@ bool ScannerRegAccess::write(unsigned int addr, const unsigned int val) } case SR_UPDATA_START: { - scanner->set_sleepstatus(false); + //scanner->set_sleepstatus(false); //安路电机板更新时需要电机板不断�? int currlenght = 0; std::vector buff; std::fstream fd; @@ -328,7 +341,7 @@ bool ScannerRegAccess::write(unsigned int addr, const unsigned int val) return true; } case SR_REBOOT: - { + { if(val >0) system("reboot loader"); else @@ -340,6 +353,14 @@ bool ScannerRegAccess::write(unsigned int addr, const unsigned int val) system("poweroff"); return true; } + case SR_SET_STARTBACKUP: + { + printf("start Back up system\n"); + system("touch /etc/back_status"); + system("echo 0 > /etc/back_status"); + system("/etc/hgbackup_auto.sh &"); + return true; + } case SR_SET_H_RATIO: case SR_SET_V_RATIO: case SR_SET_H_200_RATIO: @@ -411,20 +432,11 @@ bool ScannerRegAccess::write(unsigned int addr, const unsigned int val) case SR_SET_SPEEDMODE: { auto info = getscannerinfo(); - if(scannerSp.find((SpeedMode)info.speedmode)== scannerSp.end()) - return true; - printf("\nSR_SET_SPEEDMODE %d",val); #ifdef G200 - if(val == 100 || val == 110 || val == 120 || val == 130) - info.speedmode= val; -#elif defined G100 - if(val == 70 || val == 80 || val == 90 || val == 110) - info.speedmode = val; -#elif defined G400 - if(val == 40 || val == 50 || val == 60 || val == 70 ||val == 80) + if (val == 100 || val == 140 || val == 110 || val == 120 || val == 130) info.speedmode = val; #else - if(val == 40 || val == 50 || val == 60 || val == 70) + if (val == 100 || val == 70 || val == 80 || val == 90 || val == 110) info.speedmode = val; #endif setcameraparmSp(val); @@ -522,6 +534,26 @@ bool ScannerRegAccess::write(unsigned int addr, const unsigned int val) file_pos = val; return true; } + case SR_SET_AUTOMATICCONTROLFEEDMODE_ENABLE: + { + if(val == 0) + MotorboardParam().GetOrSetEnableAutomaticControlFeedMode(false,0); + else + MotorboardParam().GetOrSetEnableAutomaticControlFeedMode(false,1); + return true; + } + case SR_SET_AUTOMATICCONTROLFEEDMODE_THRESHOLD: + { + float fx = *((float *)&val); + printf("\n SR_SET_AUTOMATICCONTROLFEEDMODE_THRESHOLD %f",fx); + if(fx >0 && fx < 1) + { + auto param_tmp = MotorboardParam().GetParam(); + param_tmp.automaticcontrolfeedmode_threshold = fx; + MotorboardParam().SaveParam(param_tmp); + } + return true; + } case SR_SET_LOCK_STATES: { printf("\n SR_SET_LOCK_STATES %d",val); @@ -564,6 +596,9 @@ bool ScannerRegAccess::write(unsigned int addr, const unsigned int val) token.resize(val); recieve->read_bulk(&token[0],val); m_token = token; + printf("\n token = "); + for(int i =0;iwrite_bulk(&tmp[0],val); return true; } - case SR_SET_STARTBACKUP: - { - printf("start Back up system\n"); - system("touch /etc/back_status"); - system("echo 0 > /etc/back_status"); - system("/etc/hgbackup_auto.sh &"); - return true; - } case SR_CLEAN_PAPER_ROAD: - { - if(!scanner->is_runscan()) - scanner->clean_paper_road(); + scanner->clean_paper_road(); return true; - } - case SR_EXECUTE_CMD: { std::string cmd; @@ -623,7 +646,7 @@ bool ScannerRegAccess::read(unsigned int addr, unsigned int &val) switch (addr) { case SR_STATUS: - val = scanner->is_runscan() | ((!usbimages->empty()) << 1) | scanner->paper_ready() << 2; + val = scanner->is_runscan() | ((!usbimages->empty()) << 1) | scanner->paper_ready() << 2;//1/0 (1/0 << 1 | 1/0<< 2) LOG_TRACE(string_format("run status:%d", val)); return true; case SR_SCAN_COUNT: @@ -683,6 +706,12 @@ bool ScannerRegAccess::read(unsigned int addr, unsigned int &val) } return true; } + case SR_GET_BACKUPSTATUS: + { + std::ifstream i("/etc/back_status"); + i>> val; + return true; + } case SR_UPDATA_REBOOT: { if (m_upstautus == MD5_Rboot) @@ -845,6 +874,27 @@ bool ScannerRegAccess::read(unsigned int addr, unsigned int &val) val = file_pos; return true; } + case SR_GET_FEEDMODE: + { + val = MotorboardParam().GetOrSetFeedMode(true,0); + return true; + } + case SR_GET_TRAYPOSITION: + { + val = MotorboardParam().GetOrSetTrayPosition(true,0); + return true; + } + case SR_GET_AUTOMATICCONTROLFEEDMODE_ENABLE: + { + val = MotorboardParam().GetOrSetEnableAutomaticControlFeedMode(true,0); + return true; + } + case SR_GET_AUTOMATICCONTROLFEEDMODE_THRESHOLD: + { + float tmp = MotorboardParam().GetParam().automaticcontrolfeedmode_threshold; + val = *((unsigned int *)&tmp); + return true; + } case SR_GET_LOCK_STATES: { val = DeviceConfig().GetParam().is_lock; @@ -857,12 +907,6 @@ bool ScannerRegAccess::read(unsigned int addr, unsigned int &val) val = tmp.length(); return true; } - case SR_GET_BACKUPSTATUS: - { - std::ifstream i("/etc/back_status"); - i>> val; - return true; - } case SR_EXECUTE_CMD_OUT_LENGHT: { val = cmd_out.size(); @@ -879,9 +923,9 @@ bool ScannerRegAccess::cmd(const unsigned int val) switch (val) { case SC_START: - if(scanner->check_scan(m_token)) - scanner->start_scan(); + scanner->try_scan(m_token); m_token = "null"; + //scanner->start_scan(); return true; case SC_STOP: scanner->stop_scan(); @@ -1007,8 +1051,6 @@ void ScannerRegAccess::set_image_callback(void(*cb)(MemoryPtr, bool, void*), voi void ScannerRegAccess::setcameraparmSp(int speedmode){ if(cameraparmSp.find(SpeedMode(speedmode)) == cameraparmSp.end()) return ; - printf("\nSetcameraparmSp %d",speedmode); -#if defined (G100) ||defined (G200) CorrectParam cparam; for(int i=1;i<4;i++) { @@ -1031,44 +1073,4 @@ void ScannerRegAccess::setcameraparmSp(int speedmode){ cparam.SaveCorrectParam(param); } } -#elif defined (G300) || defined (G400) - MotorConfig().reset_json(); - MotorConfig::MTBDType m_mttype; - int index = 0; - if(Dail().GetValue().dails.in_voltage4 != 0) - index = 60; - switch (speedmode) - { - case 40: index += 0 ;break; - case 50: index += 6 ;break; - case 60: index += 12 ;break; - case 70: index += 18 ;break; - case 80: index += 24 ;break; - default: - break; - } - CorrectParam cparam; - for(int i=1;i<4;i++) - { - for(int j =0; j<2;j++) - { - auto param = cparam.GetFpgaparam(i,j); - if((j==1)&& (i==1)) - param.Sp = m_motor_params[index+1].sp; - if((j==0)&& (i==1)) - param.Sp = m_motor_params[index].sp; - if((j==1)&& (i==2)) - param.Sp = m_motor_params[index+3].sp; - if((j==0)&& (i==2)) - param.Sp = m_motor_params[index+2].sp; - if((j==1)&& (i==3)) - param.Sp = m_motor_params[index+5].sp; - if((j==0)&& (i==3)) - param.Sp = m_motor_params[index+4].sp; - printf("\n param.Sp = %d", param.Sp); - cparam.SaveCorrectParam(param); - } - } -#endif - -} +} \ No newline at end of file diff --git a/device/gxx-linux/scanner/scannerregs.h b/device/gxx-linux/scanner/scannerregs.h index a6da03d..dca0f65 100644 --- a/device/gxx-linux/scanner/scannerregs.h +++ b/device/gxx-linux/scanner/scannerregs.h @@ -29,9 +29,9 @@ private: bool cmd(const unsigned int val); bool procscannerinfo(unsigned int addr,unsigned int& value); Updata_Stautus m_upstautus; + std::string cmd_out; std::string jsonpath; std::string m_token; - std::string cmd_out; volatile std::uint32_t file_pos; std::shared_ptr scanner; std::shared_ptr usbimages; diff --git a/device/gxx-linux/scanner/wakeup.hpp b/device/gxx-linux/scanner/wakeup.hpp index ee94a59..8a89227 100644 --- a/device/gxx-linux/scanner/wakeup.hpp +++ b/device/gxx-linux/scanner/wakeup.hpp @@ -148,7 +148,6 @@ private: } if(event.type == 0x01 && event.code == 0x3e && event.value == 0x00) { - if(std::chrono::duration(std::chrono::steady_clock::now() - pressed_time).count() > 5000){ printf("wake up poweroff .\n"); system("poweroff"); @@ -169,6 +168,8 @@ private: printf("error sleep index.\n"); } } + + } } } diff --git a/device/gxx-linux/scanner/xmake.lua b/device/gxx-linux/scanner/xmake.lua index f33dd5c..98adcf0 100644 --- a/device/gxx-linux/scanner/xmake.lua +++ b/device/gxx-linux/scanner/xmake.lua @@ -4,8 +4,8 @@ target("gscanner") set_kind("static") add_files("*.cpp") add_syslinks("pthread") - add_links("ssl","crypto") -- add_links("turbojpeg") + add_links("ssl","crypto") add_deps("motorboard", "capimage", "gusb", "gimgproc", "applog","fpgaupdate") add_packages("common") add_includedirs(".", { public = true}) \ No newline at end of file diff --git a/device/gxx-linux/scannerinfo.json b/device/gxx-linux/scannerinfo.json deleted file mode 100644 index 1a6d878..0000000 --- a/device/gxx-linux/scannerinfo.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "ColorSp": 636, - "DoubleNum": 0, - "FeedError": 0, - "FlatClrMaxBrt": 180, - "FlatGrayMaxBrt": 180, - "GraySp": 1909, - "HRatio": 1065353216, - "JamInNum": 0, - "PID": 569, - "RollerNum": 3052, - "ScanTimes": 0, - "ScannerToken": "abcdefghijklmnopqrstuvwxyz012345", - "SerialNum": "G2396021071101", - "Sleeptime": -1, - "SpeedMode": 100, - "TotalScanned": 3052, - "VID": 12402, - "VRatio": 1065353216 -} diff --git a/device/gxx-linux/scanservice/main.cpp b/device/gxx-linux/scanservice/main.cpp index d5f1d85..6f8cdd4 100644 --- a/device/gxx-linux/scanservice/main.cpp +++ b/device/gxx-linux/scanservice/main.cpp @@ -1,239 +1,3 @@ -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include "filetools.h" -// #include "stringex.hpp" -// #include -// #include "usbservice.h" -// #include "Capturer.h" -// #include "motorboard.h" -// #include "itransmit.h" -// #include "scannerregs.h" -// #include "scanner.h" -// #include "inotify.h" -// #include "memoryex.h" -// #include "usbimageprocqueue.h" -// #include "imageusbtesthandler.h" -// #include "applog.h" -// #include "jsonconfig.h" -// #include "wakeup.hpp" - -// using namespace std; -// #define MY_PID_FILE "/tmp/scanservice_pid" -// #define BUF_LEN_FOR_PID 64 - -// static int write_pid_into_fd(int fd, pid_t pid) -// { -// int ret = -1; -// char buf[BUF_LEN_FOR_PID] = {0}; - -// /* Move cursor to the start of file. */ -// lseek(fd, 0, SEEK_SET); - -// sprintf(buf, "%d", pid); -// ret = write(fd, buf, strlen(buf)); -// if (ret <= 0) -// { /* Write fail or write 0 byte */ -// if (ret == -1) -// perror("Write " MY_PID_FILE " fail\n"); - -// ret = -1; -// } -// else -// { -// printf("Create " MY_PID_FILE " ok, pid=%d\n", pid); -// ret = 0; -// } - -// return ret; -// } - -// static int create_pid_file(pid_t pid) -// { -// int fd, ret; -// char buf[BUF_LEN_FOR_PID] = {0}; - -// fd = open(MY_PID_FILE, O_WRONLY | O_CREAT | O_EXCL, 0666); /* rw-rw-rw- */ -// if (fd == -1) -// { -// perror("Create " MY_PID_FILE " fail\n"); -// return -1; -// } - -// ret = flock(fd, LOCK_EX); -// if (ret == -1) -// { -// perror("flock " MY_PID_FILE " fail\n"); -// close(fd); -// return -1; -// } - -// ret = write_pid_into_fd(fd, pid); - -// flock(fd, LOCK_UN); -// close(fd); - -// return ret; -// } - -// static int check_pid_file(int fd, pid_t pid) -// { -// int ret = -1; -// pid_t old_pid; -// char buf[BUF_LEN_FOR_PID] = {0}; - -// ret = flock(fd, LOCK_EX); -// if (ret == -1) -// { -// perror("flock " MY_PID_FILE " fail\n"); -// return -1; -// } - -// ret = read(fd, buf, sizeof(buf) - 1); -// if (ret < 0) -// { /* read error */ -// perror("read from " MY_PID_FILE " fail\n"); -// ret = -1; -// } -// else if (ret > 0) -// { /* read ok */ -// old_pid = atol(buf); - -// /* Check if old_pid is running */ -// ret = kill(old_pid, 0); -// if (ret < 0) -// { -// if (errno == ESRCH) -// { /* old_pid is not running. */ -// ret = write_pid_into_fd(fd, pid); -// } -// else -// { -// perror("send signal fail\n"); -// ret = -1; -// } -// } -// else -// { /* running */ -// printf("Program already exists, pid=%d\n", old_pid); -// ret = -1; -// } -// } -// else if (ret == 0) -// { /* read 0 byte from file */ -// ret = write_pid_into_fd(fd, pid); -// } - -// flock(fd, LOCK_UN); - -// return ret; -// } - -// static int init_pid_file() -// { -// pid_t pid; -// int fd, ret; - -// pid = getpid(); - -// fd = open(MY_PID_FILE, O_RDWR); -// if (fd == -1) -// { /* open file fail */ -// if (errno == ENOENT) -// { /* No such file. Create one for this program. */ -// ret = create_pid_file(pid); -// } -// else -// { -// perror("open " MY_PID_FILE " fail\n"); -// ret = -1; -// } -// } -// else -// { /* pid file already exists */ -// ret = check_pid_file(fd, pid); -// close(fd); -// } - -// return ret; -// } - - - -// static void sigHandler(int sig) -// { -// if (sig == SIGINT || sig == SIGTERM) -// remove(MY_PID_FILE); -// printf("exit now \n"); -// _exit(0); -// } - - -// int main() -// { - -// if (-1 == init_pid_file()) -// { -// exit(-1); -// } - -// /* Ctrl + C */ -// if (signal(SIGINT, sigHandler) == SIG_ERR) -// { -// exit(-1); -// } - -// /* kill pid / killall name */ -// if (signal(SIGTERM, sigHandler) == SIG_ERR) -// { -// exit(-1); -// } -// auto wake = std::shared_ptr(new WakeUp()); -// auto cap = std::shared_ptr(new Capturer()); -// auto mt = std::shared_ptr(new MotorBoard()); - -// wake->setinitcallback([&mt,&cap]{ -// std::this_thread::sleep_for(std::chrono::milliseconds(5000)); -// cap->Fpga_regsAccess_reset(true); -// mt->init_statecontrol(); -// },[&mt,&cap]{ -// cap->Fpga_regsAccess_reset(false); -// mt->release_statecontrol(); -// }); -// auto scanner = std::shared_ptr(new Scanner(cap, mt,wake)); -// UsbService us(cap->regs(), mt->regs()); -// auto usbhotplugcall = [&](bool connect){ -// if(connect){ -// printf("USB Connect\n"); -// }else -// { -// scanner->stop_scan(); -// printf("USB Disconnect Scanner STOP SCAN\n"); -// exit(0); -// } - -// }; -// us.set_onconnect_call(usbhotplugcall); -// auto notify = us.notify(); - -// std::shared_ptr usbImage(new UsbImageProcQueue(notify)); -// auto transfer = us.transmiter(); -// auto receiver = us.receiver(); -// std::shared_ptr regs = std::shared_ptr(new ScannerRegAccess(scanner, usbImage, transfer,receiver)); -// scanner->set_imagehandler(std::shared_ptr(new ImageUsbHandler(usbImage))); -// us.set_scannerregs(regs); -// while(1) {std::this_thread::sleep_for(std::chrono::milliseconds(2));} -// return 0; -// } - #include #include #include @@ -246,13 +10,11 @@ #include #include #include "filetools.h" +#include "stringex.hpp" #include #include "usbservice.h" +#include "ICapturer.h" #include "Capturer.h" -#include "Imotorboard.h" -#include "motormanager.h" -#include "iscanner.h" -#include "scannero300.h" #include "MonoCapturer.h" #include "motorboard.h" #include "itransmit.h" @@ -265,9 +27,7 @@ #include "applog.h" #include "jsonconfig.h" #include "wakeup.hpp" -#include "Led.h" -#include "dailex.hpp" - +#include "StopWatch.h" using namespace std; #define MY_PID_FILE "/tmp/scanservice_pid" #define BUF_LEN_FOR_PID 64 @@ -421,7 +181,6 @@ static void sigHandler(int sig) int main() { - if (-1 == init_pid_file()) { exit(-1); @@ -438,59 +197,41 @@ int main() { exit(-1); } - //auto deviceinfo = jsonconfig().getdeviceinfo(); auto wake = std::shared_ptr(new WakeUp()); - //auto cap = std::shared_ptr(new Capturer()); - auto cap = std::shared_ptr(new MonoCapturer()); - std::shared_ptr mt; - std::shared_ptr scanner; - mt = std::shared_ptr(new MotorManager()); - scanner = std::shared_ptr(new ScannerO300(cap, mt,wake)); - mt->GetOrSetSleepFlag(false,wake->get_status() == 0 ?true : false); - printf("\n Scan_G300"); - printf("\n 鎷ㄧ爜寮€鍏?%d",Dail().GetValue().value); - UsbService us(cap->regs(), mt->regs()); - auto usbhotplugcall = [&](bool connect){ - if(connect){ - printf("USB Connect\n"); - mt->GetOrSetUsbConnectFlag(false,true); - }else - { - scanner->stop_scan(); - StopWatch sw; - while(scanner->is_runscan() || sw.elapsed_s() < 10) - { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - mt->GetOrSetUsbConnectFlag(false,false); - printf("USB Disconnect Scanner STOP SCAN\n"); - exit(0); - } - - }; - - us.set_onconnect_call(usbhotplugcall); - auto notify = us.notify(); - std::shared_ptr usbImage(new UsbImageProcQueue(notify)); - wake->setinitcallback([&cap,&mt]{ + auto cap = std::shared_ptr(new MonoCapturer()); + auto mt = std::shared_ptr(new MotorBoard(wake)); + wake->setinitcallback([&mt,&cap]{ std::this_thread::sleep_for(std::chrono::milliseconds(5000)); cap->Fpga_regsAccess_reset(true); - mt->LedControlOption(HG_LedOption::HG_WHITE_ON,0); - mt->GetOrSetSleepFlag(false,false); - },[&mt,&cap,&usbImage,&scanner]{ - scanner->stop_scan(); - scanner->add_scansever({.From = STOPSCAN , .Code = 1}); + //cap->reset(); + mt->init_statecontrol(); + },[&mt,&cap]{ cap->Fpga_regsAccess_reset(false); - mt->LedControlOption(HG_LedOption::HG_GREEN_ON,0); - mt->GetOrSetSleepFlag(false,true); - + mt->release_statecontrol(); }); if(wake->get_status() == 0) { cap->Fpga_regsAccess_reset(false); - mt->LedControlOption(HG_LedOption::HG_GREEN_ON,0); - mt->GetOrSetSleepFlag(false,true); + mt->release_statecontrol(); } + + auto scanner = std::shared_ptr(new Scanner(cap, mt,wake)); + UsbService us(cap->regs(), mt->regs()); + auto usbhotplugcall = [&](bool connect){ + if(connect){ + printf("\nUSB Connect\n"); + }else + { + scanner->stop_scan(); + mt->release_statecontrol(); + printf("USB Disconnect Scanner STOP SCAN\n"); + exit(0); + } + }; + us.set_onconnect_call(usbhotplugcall); + auto notify = us.notify(); + + std::shared_ptr usbImage(new UsbImageProcQueue(notify)); auto transfer = us.transmiter(); auto receiver = us.receiver(); std::shared_ptr regs = std::shared_ptr(new ScannerRegAccess(scanner, usbImage, transfer,receiver)); diff --git a/device/gxx-linux/scanservice/xmake.lua b/device/gxx-linux/scanservice/xmake.lua index 0c7f929..cb20cc0 100644 --- a/device/gxx-linux/scanservice/xmake.lua +++ b/device/gxx-linux/scanservice/xmake.lua @@ -1,7 +1,10 @@ add_rules("mode.debug", "mode.release") + target("scanservice") set_kind("binary") add_files("*.cpp") add_deps("gusb", "applog") + --add_rules("utils.bin2c",{linewidth = 32,extension = {".bin"}}) + --add_files("table.bin") add_packages("common") add_deps("capimage", "motorboard", "gscanner") \ No newline at end of file diff --git a/device/gxx-linux/service/main.cpp b/device/gxx-linux/service/main.cpp index 7994b53..7818e21 100644 --- a/device/gxx-linux/service/main.cpp +++ b/device/gxx-linux/service/main.cpp @@ -25,7 +25,7 @@ int menu() { int main() { bool exit = false; - std::shared_ptr motorboard(new MotorBoard()); + std::shared_ptr motorboard(new MotorBoard(nullptr)); std::shared_ptr capturer(new Capturer()); std::shared_ptr scanner(new Scanner(capturer, motorboard,nullptr)); std::shared_ptr scannerRegs(new ScannerRegAccess(scanner)); diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/.DevUtil.o.d b/device/gxx-linux/small_lcd/app_spi_lcd/.DevUtil.o.d new file mode 100644 index 0000000..a6fd32b --- /dev/null +++ b/device/gxx-linux/small_lcd/app_spi_lcd/.DevUtil.o.d @@ -0,0 +1,170 @@ +DevUtil.o: DevUtil.cpp /usr/include/stdc-predef.h DevUtil.h \ + /usr/include/c++/8/string \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++config.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/os_defines.h \ + /usr/include/features.h /usr/include/aarch64-linux-gnu/sys/cdefs.h \ + /usr/include/aarch64-linux-gnu/bits/wordsize.h \ + /usr/include/aarch64-linux-gnu/bits/long-double.h \ + /usr/include/aarch64-linux-gnu/gnu/stubs.h \ + /usr/include/aarch64-linux-gnu/gnu/stubs-lp64.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/cpu_defines.h \ + /usr/include/c++/8/bits/stringfwd.h /usr/include/c++/8/bits/memoryfwd.h \ + /usr/include/c++/8/bits/char_traits.h \ + /usr/include/c++/8/bits/stl_algobase.h \ + /usr/include/c++/8/bits/functexcept.h \ + /usr/include/c++/8/bits/exception_defines.h \ + /usr/include/c++/8/bits/cpp_type_traits.h \ + /usr/include/c++/8/ext/type_traits.h \ + /usr/include/c++/8/ext/numeric_traits.h \ + /usr/include/c++/8/bits/stl_pair.h /usr/include/c++/8/bits/move.h \ + /usr/include/c++/8/bits/concept_check.h /usr/include/c++/8/type_traits \ + /usr/include/c++/8/bits/stl_iterator_base_types.h \ + /usr/include/c++/8/bits/stl_iterator_base_funcs.h \ + /usr/include/c++/8/debug/assertions.h \ + /usr/include/c++/8/bits/stl_iterator.h \ + /usr/include/c++/8/bits/ptr_traits.h /usr/include/c++/8/debug/debug.h \ + /usr/include/c++/8/bits/predefined_ops.h \ + /usr/include/c++/8/bits/postypes.h /usr/include/c++/8/cwchar \ + /usr/include/wchar.h \ + /usr/include/aarch64-linux-gnu/bits/libc-header-start.h \ + /usr/include/aarch64-linux-gnu/bits/floatn.h \ + /usr/include/aarch64-linux-gnu/bits/floatn-common.h \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stddef.h \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stdarg.h \ + /usr/include/aarch64-linux-gnu/bits/wchar.h \ + /usr/include/aarch64-linux-gnu/bits/types/wint_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/mbstate_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__mbstate_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/locale_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__locale_t.h \ + /usr/include/c++/8/cstdint \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stdint.h /usr/include/stdint.h \ + /usr/include/aarch64-linux-gnu/bits/types.h \ + /usr/include/aarch64-linux-gnu/bits/typesizes.h \ + /usr/include/aarch64-linux-gnu/bits/stdint-intn.h \ + /usr/include/aarch64-linux-gnu/bits/stdint-uintn.h \ + /usr/include/c++/8/bits/allocator.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++allocator.h \ + /usr/include/c++/8/ext/new_allocator.h /usr/include/c++/8/new \ + /usr/include/c++/8/exception /usr/include/c++/8/bits/exception.h \ + /usr/include/c++/8/bits/exception_ptr.h \ + /usr/include/c++/8/bits/cxxabi_init_exception.h \ + /usr/include/c++/8/typeinfo /usr/include/c++/8/bits/hash_bytes.h \ + /usr/include/c++/8/bits/nested_exception.h \ + /usr/include/c++/8/bits/localefwd.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++locale.h \ + /usr/include/c++/8/clocale /usr/include/locale.h \ + /usr/include/aarch64-linux-gnu/bits/locale.h /usr/include/c++/8/iosfwd \ + /usr/include/c++/8/cctype /usr/include/ctype.h /usr/include/endian.h \ + /usr/include/aarch64-linux-gnu/bits/endian.h \ + /usr/include/aarch64-linux-gnu/bits/byteswap.h \ + /usr/include/aarch64-linux-gnu/bits/uintn-identity.h \ + /usr/include/c++/8/bits/ostream_insert.h \ + /usr/include/c++/8/bits/cxxabi_forced.h \ + /usr/include/c++/8/bits/stl_function.h \ + /usr/include/c++/8/backward/binders.h \ + /usr/include/c++/8/bits/range_access.h \ + /usr/include/c++/8/initializer_list \ + /usr/include/c++/8/bits/basic_string.h \ + /usr/include/c++/8/ext/atomicity.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/gthr.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/gthr-default.h \ + /usr/include/pthread.h /usr/include/sched.h \ + /usr/include/aarch64-linux-gnu/bits/types/time_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_timespec.h \ + /usr/include/aarch64-linux-gnu/bits/sched.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_sched_param.h \ + /usr/include/aarch64-linux-gnu/bits/cpu-set.h /usr/include/time.h \ + /usr/include/aarch64-linux-gnu/bits/time.h \ + /usr/include/aarch64-linux-gnu/bits/timex.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_timeval.h \ + /usr/include/aarch64-linux-gnu/bits/types/clock_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_tm.h \ + /usr/include/aarch64-linux-gnu/bits/types/clockid_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/timer_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_itimerspec.h \ + /usr/include/aarch64-linux-gnu/bits/pthreadtypes.h \ + /usr/include/aarch64-linux-gnu/bits/thread-shared-types.h \ + /usr/include/aarch64-linux-gnu/bits/pthreadtypes-arch.h \ + /usr/include/aarch64-linux-gnu/bits/setjmp.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/atomic_word.h \ + /usr/include/c++/8/ext/alloc_traits.h \ + /usr/include/c++/8/bits/alloc_traits.h \ + /usr/include/c++/8/ext/string_conversions.h /usr/include/c++/8/cstdlib \ + /usr/include/stdlib.h /usr/include/aarch64-linux-gnu/bits/waitflags.h \ + /usr/include/aarch64-linux-gnu/bits/waitstatus.h \ + /usr/include/aarch64-linux-gnu/sys/types.h \ + /usr/include/aarch64-linux-gnu/sys/select.h \ + /usr/include/aarch64-linux-gnu/bits/select.h \ + /usr/include/aarch64-linux-gnu/bits/types/sigset_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__sigset_t.h \ + /usr/include/alloca.h /usr/include/aarch64-linux-gnu/bits/stdlib-float.h \ + /usr/include/c++/8/bits/std_abs.h /usr/include/c++/8/cstdio \ + /usr/include/stdio.h \ + /usr/include/aarch64-linux-gnu/bits/types/__fpos_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__fpos64_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/cookie_io_functions_t.h \ + /usr/include/aarch64-linux-gnu/bits/stdio_lim.h \ + /usr/include/aarch64-linux-gnu/bits/sys_errlist.h \ + /usr/include/c++/8/cerrno /usr/include/errno.h \ + /usr/include/aarch64-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/aarch64-linux-gnu/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/aarch64-linux-gnu/bits/types/error_t.h \ + /usr/include/c++/8/bits/functional_hash.h \ + /usr/include/c++/8/bits/basic_string.tcc /usr/include/c++/8/fstream \ + /usr/include/c++/8/istream /usr/include/c++/8/ios \ + /usr/include/c++/8/bits/ios_base.h \ + /usr/include/c++/8/bits/locale_classes.h \ + /usr/include/c++/8/bits/locale_classes.tcc \ + /usr/include/c++/8/system_error \ + /usr/include/aarch64-linux-gnu/c++/8/bits/error_constants.h \ + /usr/include/c++/8/stdexcept /usr/include/c++/8/streambuf \ + /usr/include/c++/8/bits/streambuf.tcc \ + /usr/include/c++/8/bits/basic_ios.h \ + /usr/include/c++/8/bits/locale_facets.h /usr/include/c++/8/cwctype \ + /usr/include/wctype.h /usr/include/aarch64-linux-gnu/bits/wctype-wchar.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/ctype_base.h \ + /usr/include/c++/8/bits/streambuf_iterator.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/ctype_inline.h \ + /usr/include/c++/8/bits/locale_facets.tcc \ + /usr/include/c++/8/bits/basic_ios.tcc /usr/include/c++/8/ostream \ + /usr/include/c++/8/bits/ostream.tcc /usr/include/c++/8/bits/istream.tcc \ + /usr/include/c++/8/bits/codecvt.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/basic_file.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++io.h \ + /usr/include/c++/8/bits/fstream.tcc /usr/include/c++/8/memory \ + /usr/include/c++/8/bits/stl_construct.h \ + /usr/include/c++/8/bits/stl_uninitialized.h \ + /usr/include/c++/8/bits/stl_tempbuf.h \ + /usr/include/c++/8/bits/stl_raw_storage_iter.h \ + /usr/include/c++/8/ext/concurrence.h \ + /usr/include/c++/8/bits/uses_allocator.h \ + /usr/include/c++/8/bits/unique_ptr.h /usr/include/c++/8/utility \ + /usr/include/c++/8/bits/stl_relops.h /usr/include/c++/8/tuple \ + /usr/include/c++/8/array /usr/include/c++/8/bits/invoke.h \ + /usr/include/c++/8/bits/shared_ptr.h \ + /usr/include/c++/8/bits/shared_ptr_base.h \ + /usr/include/c++/8/bits/allocated_ptr.h \ + /usr/include/c++/8/bits/refwrap.h \ + /usr/include/c++/8/ext/aligned_buffer.h \ + /usr/include/c++/8/bits/shared_ptr_atomic.h \ + /usr/include/c++/8/bits/atomic_base.h \ + /usr/include/c++/8/bits/atomic_lockfree_defines.h \ + /usr/include/c++/8/backward/auto_ptr.h /usr/include/unistd.h \ + /usr/include/aarch64-linux-gnu/bits/posix_opt.h \ + /usr/include/aarch64-linux-gnu/bits/environments.h \ + /usr/include/aarch64-linux-gnu/bits/confname.h \ + /usr/include/aarch64-linux-gnu/bits/getopt_posix.h \ + /usr/include/aarch64-linux-gnu/bits/getopt_core.h \ + /usr/include/aarch64-linux-gnu/sys/stat.h \ + /usr/include/aarch64-linux-gnu/bits/stat.h \ + /usr/include/aarch64-linux-gnu/bits/statx.h \ + /usr/include/aarch64-linux-gnu/sys/time.h /usr/include/c++/8/stdlib.h \ + /usr/include/fcntl.h /usr/include/aarch64-linux-gnu/bits/fcntl.h \ + /usr/include/aarch64-linux-gnu/bits/fcntl-linux.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_iovec.h \ + /usr/include/linux/falloc.h diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/.Gpio.o.d b/device/gxx-linux/small_lcd/app_spi_lcd/.Gpio.o.d new file mode 100644 index 0000000..e295f64 --- /dev/null +++ b/device/gxx-linux/small_lcd/app_spi_lcd/.Gpio.o.d @@ -0,0 +1,169 @@ +Gpio.o: Gpio.cpp /usr/include/stdc-predef.h Gpio.h \ + /usr/include/c++/8/string \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++config.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/os_defines.h \ + /usr/include/features.h /usr/include/aarch64-linux-gnu/sys/cdefs.h \ + /usr/include/aarch64-linux-gnu/bits/wordsize.h \ + /usr/include/aarch64-linux-gnu/bits/long-double.h \ + /usr/include/aarch64-linux-gnu/gnu/stubs.h \ + /usr/include/aarch64-linux-gnu/gnu/stubs-lp64.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/cpu_defines.h \ + /usr/include/c++/8/bits/stringfwd.h /usr/include/c++/8/bits/memoryfwd.h \ + /usr/include/c++/8/bits/char_traits.h \ + /usr/include/c++/8/bits/stl_algobase.h \ + /usr/include/c++/8/bits/functexcept.h \ + /usr/include/c++/8/bits/exception_defines.h \ + /usr/include/c++/8/bits/cpp_type_traits.h \ + /usr/include/c++/8/ext/type_traits.h \ + /usr/include/c++/8/ext/numeric_traits.h \ + /usr/include/c++/8/bits/stl_pair.h /usr/include/c++/8/bits/move.h \ + /usr/include/c++/8/bits/concept_check.h /usr/include/c++/8/type_traits \ + /usr/include/c++/8/bits/stl_iterator_base_types.h \ + /usr/include/c++/8/bits/stl_iterator_base_funcs.h \ + /usr/include/c++/8/debug/assertions.h \ + /usr/include/c++/8/bits/stl_iterator.h \ + /usr/include/c++/8/bits/ptr_traits.h /usr/include/c++/8/debug/debug.h \ + /usr/include/c++/8/bits/predefined_ops.h \ + /usr/include/c++/8/bits/postypes.h /usr/include/c++/8/cwchar \ + /usr/include/wchar.h \ + /usr/include/aarch64-linux-gnu/bits/libc-header-start.h \ + /usr/include/aarch64-linux-gnu/bits/floatn.h \ + /usr/include/aarch64-linux-gnu/bits/floatn-common.h \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stddef.h \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stdarg.h \ + /usr/include/aarch64-linux-gnu/bits/wchar.h \ + /usr/include/aarch64-linux-gnu/bits/types/wint_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/mbstate_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__mbstate_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/locale_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__locale_t.h \ + /usr/include/c++/8/cstdint \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stdint.h /usr/include/stdint.h \ + /usr/include/aarch64-linux-gnu/bits/types.h \ + /usr/include/aarch64-linux-gnu/bits/typesizes.h \ + /usr/include/aarch64-linux-gnu/bits/stdint-intn.h \ + /usr/include/aarch64-linux-gnu/bits/stdint-uintn.h \ + /usr/include/c++/8/bits/allocator.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++allocator.h \ + /usr/include/c++/8/ext/new_allocator.h /usr/include/c++/8/new \ + /usr/include/c++/8/exception /usr/include/c++/8/bits/exception.h \ + /usr/include/c++/8/bits/exception_ptr.h \ + /usr/include/c++/8/bits/cxxabi_init_exception.h \ + /usr/include/c++/8/typeinfo /usr/include/c++/8/bits/hash_bytes.h \ + /usr/include/c++/8/bits/nested_exception.h \ + /usr/include/c++/8/bits/localefwd.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++locale.h \ + /usr/include/c++/8/clocale /usr/include/locale.h \ + /usr/include/aarch64-linux-gnu/bits/locale.h /usr/include/c++/8/iosfwd \ + /usr/include/c++/8/cctype /usr/include/ctype.h /usr/include/endian.h \ + /usr/include/aarch64-linux-gnu/bits/endian.h \ + /usr/include/aarch64-linux-gnu/bits/byteswap.h \ + /usr/include/aarch64-linux-gnu/bits/uintn-identity.h \ + /usr/include/c++/8/bits/ostream_insert.h \ + /usr/include/c++/8/bits/cxxabi_forced.h \ + /usr/include/c++/8/bits/stl_function.h \ + /usr/include/c++/8/backward/binders.h \ + /usr/include/c++/8/bits/range_access.h \ + /usr/include/c++/8/initializer_list \ + /usr/include/c++/8/bits/basic_string.h \ + /usr/include/c++/8/ext/atomicity.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/gthr.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/gthr-default.h \ + /usr/include/pthread.h /usr/include/sched.h \ + /usr/include/aarch64-linux-gnu/bits/types/time_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_timespec.h \ + /usr/include/aarch64-linux-gnu/bits/sched.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_sched_param.h \ + /usr/include/aarch64-linux-gnu/bits/cpu-set.h /usr/include/time.h \ + /usr/include/aarch64-linux-gnu/bits/time.h \ + /usr/include/aarch64-linux-gnu/bits/timex.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_timeval.h \ + /usr/include/aarch64-linux-gnu/bits/types/clock_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_tm.h \ + /usr/include/aarch64-linux-gnu/bits/types/clockid_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/timer_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_itimerspec.h \ + /usr/include/aarch64-linux-gnu/bits/pthreadtypes.h \ + /usr/include/aarch64-linux-gnu/bits/thread-shared-types.h \ + /usr/include/aarch64-linux-gnu/bits/pthreadtypes-arch.h \ + /usr/include/aarch64-linux-gnu/bits/setjmp.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/atomic_word.h \ + /usr/include/c++/8/ext/alloc_traits.h \ + /usr/include/c++/8/bits/alloc_traits.h \ + /usr/include/c++/8/ext/string_conversions.h /usr/include/c++/8/cstdlib \ + /usr/include/stdlib.h /usr/include/aarch64-linux-gnu/bits/waitflags.h \ + /usr/include/aarch64-linux-gnu/bits/waitstatus.h \ + /usr/include/aarch64-linux-gnu/sys/types.h \ + /usr/include/aarch64-linux-gnu/sys/select.h \ + /usr/include/aarch64-linux-gnu/bits/select.h \ + /usr/include/aarch64-linux-gnu/bits/types/sigset_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__sigset_t.h \ + /usr/include/alloca.h /usr/include/aarch64-linux-gnu/bits/stdlib-float.h \ + /usr/include/c++/8/bits/std_abs.h /usr/include/c++/8/cstdio \ + /usr/include/stdio.h \ + /usr/include/aarch64-linux-gnu/bits/types/__fpos_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__fpos64_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/cookie_io_functions_t.h \ + /usr/include/aarch64-linux-gnu/bits/stdio_lim.h \ + /usr/include/aarch64-linux-gnu/bits/sys_errlist.h \ + /usr/include/c++/8/cerrno /usr/include/errno.h \ + /usr/include/aarch64-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/aarch64-linux-gnu/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/aarch64-linux-gnu/bits/types/error_t.h \ + /usr/include/c++/8/bits/functional_hash.h \ + /usr/include/c++/8/bits/basic_string.tcc DevUtil.h \ + /usr/include/c++/8/fstream /usr/include/c++/8/istream \ + /usr/include/c++/8/ios /usr/include/c++/8/bits/ios_base.h \ + /usr/include/c++/8/bits/locale_classes.h \ + /usr/include/c++/8/bits/locale_classes.tcc \ + /usr/include/c++/8/system_error \ + /usr/include/aarch64-linux-gnu/c++/8/bits/error_constants.h \ + /usr/include/c++/8/stdexcept /usr/include/c++/8/streambuf \ + /usr/include/c++/8/bits/streambuf.tcc \ + /usr/include/c++/8/bits/basic_ios.h \ + /usr/include/c++/8/bits/locale_facets.h /usr/include/c++/8/cwctype \ + /usr/include/wctype.h /usr/include/aarch64-linux-gnu/bits/wctype-wchar.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/ctype_base.h \ + /usr/include/c++/8/bits/streambuf_iterator.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/ctype_inline.h \ + /usr/include/c++/8/bits/locale_facets.tcc \ + /usr/include/c++/8/bits/basic_ios.tcc /usr/include/c++/8/ostream \ + /usr/include/c++/8/bits/ostream.tcc /usr/include/c++/8/bits/istream.tcc \ + /usr/include/c++/8/bits/codecvt.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/basic_file.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++io.h \ + /usr/include/c++/8/bits/fstream.tcc /usr/include/c++/8/memory \ + /usr/include/c++/8/bits/stl_construct.h \ + /usr/include/c++/8/bits/stl_uninitialized.h \ + /usr/include/c++/8/bits/stl_tempbuf.h \ + /usr/include/c++/8/bits/stl_raw_storage_iter.h \ + /usr/include/c++/8/ext/concurrence.h \ + /usr/include/c++/8/bits/uses_allocator.h \ + /usr/include/c++/8/bits/unique_ptr.h /usr/include/c++/8/utility \ + /usr/include/c++/8/bits/stl_relops.h /usr/include/c++/8/tuple \ + /usr/include/c++/8/array /usr/include/c++/8/bits/invoke.h \ + /usr/include/c++/8/bits/shared_ptr.h \ + /usr/include/c++/8/bits/shared_ptr_base.h \ + /usr/include/c++/8/bits/allocated_ptr.h \ + /usr/include/c++/8/bits/refwrap.h \ + /usr/include/c++/8/ext/aligned_buffer.h \ + /usr/include/c++/8/bits/shared_ptr_atomic.h \ + /usr/include/c++/8/bits/atomic_base.h \ + /usr/include/c++/8/bits/atomic_lockfree_defines.h \ + /usr/include/c++/8/backward/auto_ptr.h \ + /usr/include/aarch64-linux-gnu/sys/stat.h \ + /usr/include/aarch64-linux-gnu/bits/stat.h \ + /usr/include/aarch64-linux-gnu/bits/statx.h /usr/include/fcntl.h \ + /usr/include/aarch64-linux-gnu/bits/fcntl.h \ + /usr/include/aarch64-linux-gnu/bits/fcntl-linux.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_iovec.h \ + /usr/include/linux/falloc.h /usr/include/unistd.h \ + /usr/include/aarch64-linux-gnu/bits/posix_opt.h \ + /usr/include/aarch64-linux-gnu/bits/environments.h \ + /usr/include/aarch64-linux-gnu/bits/confname.h \ + /usr/include/aarch64-linux-gnu/bits/getopt_posix.h \ + /usr/include/aarch64-linux-gnu/bits/getopt_core.h diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/.Lcd.o.d b/device/gxx-linux/small_lcd/app_spi_lcd/.Lcd.o.d new file mode 100644 index 0000000..404f7b7 --- /dev/null +++ b/device/gxx-linux/small_lcd/app_spi_lcd/.Lcd.o.d @@ -0,0 +1,172 @@ +Lcd.o: Lcd.cpp /usr/include/stdc-predef.h Lcd.h /usr/include/stdio.h \ + /usr/include/aarch64-linux-gnu/bits/libc-header-start.h \ + /usr/include/features.h /usr/include/aarch64-linux-gnu/sys/cdefs.h \ + /usr/include/aarch64-linux-gnu/bits/wordsize.h \ + /usr/include/aarch64-linux-gnu/bits/long-double.h \ + /usr/include/aarch64-linux-gnu/gnu/stubs.h \ + /usr/include/aarch64-linux-gnu/gnu/stubs-lp64.h \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stddef.h \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stdarg.h \ + /usr/include/aarch64-linux-gnu/bits/types.h \ + /usr/include/aarch64-linux-gnu/bits/typesizes.h \ + /usr/include/aarch64-linux-gnu/bits/types/__fpos_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__mbstate_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__fpos64_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/cookie_io_functions_t.h \ + /usr/include/aarch64-linux-gnu/bits/stdio_lim.h \ + /usr/include/aarch64-linux-gnu/bits/sys_errlist.h \ + /usr/include/c++/8/stdlib.h /usr/include/c++/8/cstdlib \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++config.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/os_defines.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/cpu_defines.h \ + /usr/include/stdlib.h /usr/include/aarch64-linux-gnu/bits/waitflags.h \ + /usr/include/aarch64-linux-gnu/bits/waitstatus.h \ + /usr/include/aarch64-linux-gnu/bits/floatn.h \ + /usr/include/aarch64-linux-gnu/bits/floatn-common.h \ + /usr/include/aarch64-linux-gnu/bits/types/locale_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__locale_t.h \ + /usr/include/aarch64-linux-gnu/sys/types.h \ + /usr/include/aarch64-linux-gnu/bits/types/clock_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/clockid_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/time_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/timer_t.h \ + /usr/include/aarch64-linux-gnu/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/aarch64-linux-gnu/bits/endian.h \ + /usr/include/aarch64-linux-gnu/bits/byteswap.h \ + /usr/include/aarch64-linux-gnu/bits/uintn-identity.h \ + /usr/include/aarch64-linux-gnu/sys/select.h \ + /usr/include/aarch64-linux-gnu/bits/select.h \ + /usr/include/aarch64-linux-gnu/bits/types/sigset_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__sigset_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_timeval.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_timespec.h \ + /usr/include/aarch64-linux-gnu/bits/pthreadtypes.h \ + /usr/include/aarch64-linux-gnu/bits/thread-shared-types.h \ + /usr/include/aarch64-linux-gnu/bits/pthreadtypes-arch.h \ + /usr/include/alloca.h /usr/include/aarch64-linux-gnu/bits/stdlib-float.h \ + /usr/include/c++/8/bits/std_abs.h /usr/include/c++/8/sstream \ + /usr/include/c++/8/istream /usr/include/c++/8/ios \ + /usr/include/c++/8/iosfwd /usr/include/c++/8/bits/stringfwd.h \ + /usr/include/c++/8/bits/memoryfwd.h /usr/include/c++/8/bits/postypes.h \ + /usr/include/c++/8/cwchar /usr/include/wchar.h \ + /usr/include/aarch64-linux-gnu/bits/wchar.h \ + /usr/include/aarch64-linux-gnu/bits/types/wint_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/mbstate_t.h \ + /usr/include/c++/8/exception /usr/include/c++/8/bits/exception.h \ + /usr/include/c++/8/bits/exception_ptr.h \ + /usr/include/c++/8/bits/exception_defines.h \ + /usr/include/c++/8/bits/cxxabi_init_exception.h \ + /usr/include/c++/8/typeinfo /usr/include/c++/8/bits/hash_bytes.h \ + /usr/include/c++/8/new /usr/include/c++/8/bits/nested_exception.h \ + /usr/include/c++/8/bits/move.h /usr/include/c++/8/bits/concept_check.h \ + /usr/include/c++/8/type_traits /usr/include/c++/8/bits/char_traits.h \ + /usr/include/c++/8/bits/stl_algobase.h \ + /usr/include/c++/8/bits/functexcept.h \ + /usr/include/c++/8/bits/cpp_type_traits.h \ + /usr/include/c++/8/ext/type_traits.h \ + /usr/include/c++/8/ext/numeric_traits.h \ + /usr/include/c++/8/bits/stl_pair.h \ + /usr/include/c++/8/bits/stl_iterator_base_types.h \ + /usr/include/c++/8/bits/stl_iterator_base_funcs.h \ + /usr/include/c++/8/debug/assertions.h \ + /usr/include/c++/8/bits/stl_iterator.h \ + /usr/include/c++/8/bits/ptr_traits.h /usr/include/c++/8/debug/debug.h \ + /usr/include/c++/8/bits/predefined_ops.h /usr/include/c++/8/cstdint \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stdint.h /usr/include/stdint.h \ + /usr/include/aarch64-linux-gnu/bits/stdint-uintn.h \ + /usr/include/c++/8/bits/localefwd.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++locale.h \ + /usr/include/c++/8/clocale /usr/include/locale.h \ + /usr/include/aarch64-linux-gnu/bits/locale.h /usr/include/c++/8/cctype \ + /usr/include/ctype.h /usr/include/c++/8/bits/ios_base.h \ + /usr/include/c++/8/ext/atomicity.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/gthr.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/gthr-default.h \ + /usr/include/pthread.h /usr/include/sched.h \ + /usr/include/aarch64-linux-gnu/bits/sched.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_sched_param.h \ + /usr/include/aarch64-linux-gnu/bits/cpu-set.h /usr/include/time.h \ + /usr/include/aarch64-linux-gnu/bits/time.h \ + /usr/include/aarch64-linux-gnu/bits/timex.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_tm.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_itimerspec.h \ + /usr/include/aarch64-linux-gnu/bits/setjmp.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/atomic_word.h \ + /usr/include/c++/8/bits/locale_classes.h /usr/include/c++/8/string \ + /usr/include/c++/8/bits/allocator.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++allocator.h \ + /usr/include/c++/8/ext/new_allocator.h \ + /usr/include/c++/8/bits/ostream_insert.h \ + /usr/include/c++/8/bits/cxxabi_forced.h \ + /usr/include/c++/8/bits/stl_function.h \ + /usr/include/c++/8/backward/binders.h \ + /usr/include/c++/8/bits/range_access.h \ + /usr/include/c++/8/initializer_list \ + /usr/include/c++/8/bits/basic_string.h \ + /usr/include/c++/8/ext/alloc_traits.h \ + /usr/include/c++/8/bits/alloc_traits.h \ + /usr/include/c++/8/ext/string_conversions.h /usr/include/c++/8/cstdio \ + /usr/include/c++/8/cerrno /usr/include/errno.h \ + /usr/include/aarch64-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/aarch64-linux-gnu/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/aarch64-linux-gnu/bits/types/error_t.h \ + /usr/include/c++/8/bits/functional_hash.h \ + /usr/include/c++/8/bits/basic_string.tcc \ + /usr/include/c++/8/bits/locale_classes.tcc \ + /usr/include/c++/8/system_error \ + /usr/include/aarch64-linux-gnu/c++/8/bits/error_constants.h \ + /usr/include/c++/8/stdexcept /usr/include/c++/8/streambuf \ + /usr/include/c++/8/bits/streambuf.tcc \ + /usr/include/c++/8/bits/basic_ios.h \ + /usr/include/c++/8/bits/locale_facets.h /usr/include/c++/8/cwctype \ + /usr/include/wctype.h /usr/include/aarch64-linux-gnu/bits/wctype-wchar.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/ctype_base.h \ + /usr/include/c++/8/bits/streambuf_iterator.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/ctype_inline.h \ + /usr/include/c++/8/bits/locale_facets.tcc \ + /usr/include/c++/8/bits/basic_ios.tcc /usr/include/c++/8/ostream \ + /usr/include/c++/8/bits/ostream.tcc /usr/include/c++/8/bits/istream.tcc \ + /usr/include/c++/8/bits/sstream.tcc /usr/include/unistd.h \ + /usr/include/aarch64-linux-gnu/bits/posix_opt.h \ + /usr/include/aarch64-linux-gnu/bits/environments.h \ + /usr/include/aarch64-linux-gnu/bits/confname.h \ + /usr/include/aarch64-linux-gnu/bits/getopt_posix.h \ + /usr/include/aarch64-linux-gnu/bits/getopt_core.h DevUtil.h \ + /usr/include/c++/8/fstream /usr/include/c++/8/bits/codecvt.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/basic_file.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++io.h \ + /usr/include/c++/8/bits/fstream.tcc /usr/include/c++/8/memory \ + /usr/include/c++/8/bits/stl_construct.h \ + /usr/include/c++/8/bits/stl_uninitialized.h \ + /usr/include/c++/8/bits/stl_tempbuf.h \ + /usr/include/c++/8/bits/stl_raw_storage_iter.h \ + /usr/include/c++/8/ext/concurrence.h \ + /usr/include/c++/8/bits/uses_allocator.h \ + /usr/include/c++/8/bits/unique_ptr.h /usr/include/c++/8/utility \ + /usr/include/c++/8/bits/stl_relops.h /usr/include/c++/8/tuple \ + /usr/include/c++/8/array /usr/include/c++/8/bits/invoke.h \ + /usr/include/c++/8/bits/shared_ptr.h \ + /usr/include/c++/8/bits/shared_ptr_base.h \ + /usr/include/c++/8/bits/allocated_ptr.h \ + /usr/include/c++/8/bits/refwrap.h \ + /usr/include/c++/8/ext/aligned_buffer.h \ + /usr/include/c++/8/bits/shared_ptr_atomic.h \ + /usr/include/c++/8/bits/atomic_base.h \ + /usr/include/c++/8/bits/atomic_lockfree_defines.h \ + /usr/include/c++/8/backward/auto_ptr.h filetools.h \ + /usr/include/c++/8/vector /usr/include/c++/8/bits/stl_vector.h \ + /usr/include/c++/8/bits/stl_bvector.h /usr/include/c++/8/bits/vector.tcc \ + /usr/include/c++/8/chrono /usr/include/c++/8/ratio \ + /usr/include/c++/8/limits /usr/include/c++/8/ctime \ + /usr/include/c++/8/bits/parse_numbers.h Gpio.h \ + /usr/include/aarch64-linux-gnu/sys/stat.h \ + /usr/include/aarch64-linux-gnu/bits/stat.h \ + /usr/include/aarch64-linux-gnu/bits/statx.h /usr/include/fcntl.h \ + /usr/include/aarch64-linux-gnu/bits/fcntl.h \ + /usr/include/aarch64-linux-gnu/bits/fcntl-linux.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_iovec.h \ + /usr/include/linux/falloc.h diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/.main.o.d b/device/gxx-linux/small_lcd/app_spi_lcd/.main.o.d new file mode 100644 index 0000000..3a116f4 --- /dev/null +++ b/device/gxx-linux/small_lcd/app_spi_lcd/.main.o.d @@ -0,0 +1,172 @@ +main.o: main.cpp /usr/include/stdc-predef.h /usr/include/stdio.h \ + /usr/include/aarch64-linux-gnu/bits/libc-header-start.h \ + /usr/include/features.h /usr/include/aarch64-linux-gnu/sys/cdefs.h \ + /usr/include/aarch64-linux-gnu/bits/wordsize.h \ + /usr/include/aarch64-linux-gnu/bits/long-double.h \ + /usr/include/aarch64-linux-gnu/gnu/stubs.h \ + /usr/include/aarch64-linux-gnu/gnu/stubs-lp64.h \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stddef.h \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stdarg.h \ + /usr/include/aarch64-linux-gnu/bits/types.h \ + /usr/include/aarch64-linux-gnu/bits/typesizes.h \ + /usr/include/aarch64-linux-gnu/bits/types/__fpos_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__mbstate_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__fpos64_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_FILE.h \ + /usr/include/aarch64-linux-gnu/bits/types/cookie_io_functions_t.h \ + /usr/include/aarch64-linux-gnu/bits/stdio_lim.h \ + /usr/include/aarch64-linux-gnu/bits/sys_errlist.h \ + /usr/include/c++/8/stdlib.h /usr/include/c++/8/cstdlib \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++config.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/os_defines.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/cpu_defines.h \ + /usr/include/stdlib.h /usr/include/aarch64-linux-gnu/bits/waitflags.h \ + /usr/include/aarch64-linux-gnu/bits/waitstatus.h \ + /usr/include/aarch64-linux-gnu/bits/floatn.h \ + /usr/include/aarch64-linux-gnu/bits/floatn-common.h \ + /usr/include/aarch64-linux-gnu/bits/types/locale_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__locale_t.h \ + /usr/include/aarch64-linux-gnu/sys/types.h \ + /usr/include/aarch64-linux-gnu/bits/types/clock_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/clockid_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/time_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/timer_t.h \ + /usr/include/aarch64-linux-gnu/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/aarch64-linux-gnu/bits/endian.h \ + /usr/include/aarch64-linux-gnu/bits/byteswap.h \ + /usr/include/aarch64-linux-gnu/bits/uintn-identity.h \ + /usr/include/aarch64-linux-gnu/sys/select.h \ + /usr/include/aarch64-linux-gnu/bits/select.h \ + /usr/include/aarch64-linux-gnu/bits/types/sigset_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/__sigset_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_timeval.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_timespec.h \ + /usr/include/aarch64-linux-gnu/bits/pthreadtypes.h \ + /usr/include/aarch64-linux-gnu/bits/thread-shared-types.h \ + /usr/include/aarch64-linux-gnu/bits/pthreadtypes-arch.h \ + /usr/include/alloca.h /usr/include/aarch64-linux-gnu/bits/stdlib-float.h \ + /usr/include/c++/8/bits/std_abs.h /usr/include/c++/8/sstream \ + /usr/include/c++/8/istream /usr/include/c++/8/ios \ + /usr/include/c++/8/iosfwd /usr/include/c++/8/bits/stringfwd.h \ + /usr/include/c++/8/bits/memoryfwd.h /usr/include/c++/8/bits/postypes.h \ + /usr/include/c++/8/cwchar /usr/include/wchar.h \ + /usr/include/aarch64-linux-gnu/bits/wchar.h \ + /usr/include/aarch64-linux-gnu/bits/types/wint_t.h \ + /usr/include/aarch64-linux-gnu/bits/types/mbstate_t.h \ + /usr/include/c++/8/exception /usr/include/c++/8/bits/exception.h \ + /usr/include/c++/8/bits/exception_ptr.h \ + /usr/include/c++/8/bits/exception_defines.h \ + /usr/include/c++/8/bits/cxxabi_init_exception.h \ + /usr/include/c++/8/typeinfo /usr/include/c++/8/bits/hash_bytes.h \ + /usr/include/c++/8/new /usr/include/c++/8/bits/nested_exception.h \ + /usr/include/c++/8/bits/move.h /usr/include/c++/8/bits/concept_check.h \ + /usr/include/c++/8/type_traits /usr/include/c++/8/bits/char_traits.h \ + /usr/include/c++/8/bits/stl_algobase.h \ + /usr/include/c++/8/bits/functexcept.h \ + /usr/include/c++/8/bits/cpp_type_traits.h \ + /usr/include/c++/8/ext/type_traits.h \ + /usr/include/c++/8/ext/numeric_traits.h \ + /usr/include/c++/8/bits/stl_pair.h \ + /usr/include/c++/8/bits/stl_iterator_base_types.h \ + /usr/include/c++/8/bits/stl_iterator_base_funcs.h \ + /usr/include/c++/8/debug/assertions.h \ + /usr/include/c++/8/bits/stl_iterator.h \ + /usr/include/c++/8/bits/ptr_traits.h /usr/include/c++/8/debug/debug.h \ + /usr/include/c++/8/bits/predefined_ops.h /usr/include/c++/8/cstdint \ + /usr/lib/gcc/aarch64-linux-gnu/8/include/stdint.h /usr/include/stdint.h \ + /usr/include/aarch64-linux-gnu/bits/stdint-uintn.h \ + /usr/include/c++/8/bits/localefwd.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++locale.h \ + /usr/include/c++/8/clocale /usr/include/locale.h \ + /usr/include/aarch64-linux-gnu/bits/locale.h /usr/include/c++/8/cctype \ + /usr/include/ctype.h /usr/include/c++/8/bits/ios_base.h \ + /usr/include/c++/8/ext/atomicity.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/gthr.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/gthr-default.h \ + /usr/include/pthread.h /usr/include/sched.h \ + /usr/include/aarch64-linux-gnu/bits/sched.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_sched_param.h \ + /usr/include/aarch64-linux-gnu/bits/cpu-set.h /usr/include/time.h \ + /usr/include/aarch64-linux-gnu/bits/time.h \ + /usr/include/aarch64-linux-gnu/bits/timex.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_tm.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_itimerspec.h \ + /usr/include/aarch64-linux-gnu/bits/setjmp.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/atomic_word.h \ + /usr/include/c++/8/bits/locale_classes.h /usr/include/c++/8/string \ + /usr/include/c++/8/bits/allocator.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++allocator.h \ + /usr/include/c++/8/ext/new_allocator.h \ + /usr/include/c++/8/bits/ostream_insert.h \ + /usr/include/c++/8/bits/cxxabi_forced.h \ + /usr/include/c++/8/bits/stl_function.h \ + /usr/include/c++/8/backward/binders.h \ + /usr/include/c++/8/bits/range_access.h \ + /usr/include/c++/8/initializer_list \ + /usr/include/c++/8/bits/basic_string.h \ + /usr/include/c++/8/ext/alloc_traits.h \ + /usr/include/c++/8/bits/alloc_traits.h \ + /usr/include/c++/8/ext/string_conversions.h /usr/include/c++/8/cstdio \ + /usr/include/c++/8/cerrno /usr/include/errno.h \ + /usr/include/aarch64-linux-gnu/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/aarch64-linux-gnu/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/aarch64-linux-gnu/bits/types/error_t.h \ + /usr/include/c++/8/bits/functional_hash.h \ + /usr/include/c++/8/bits/basic_string.tcc \ + /usr/include/c++/8/bits/locale_classes.tcc \ + /usr/include/c++/8/system_error \ + /usr/include/aarch64-linux-gnu/c++/8/bits/error_constants.h \ + /usr/include/c++/8/stdexcept /usr/include/c++/8/streambuf \ + /usr/include/c++/8/bits/streambuf.tcc \ + /usr/include/c++/8/bits/basic_ios.h \ + /usr/include/c++/8/bits/locale_facets.h /usr/include/c++/8/cwctype \ + /usr/include/wctype.h /usr/include/aarch64-linux-gnu/bits/wctype-wchar.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/ctype_base.h \ + /usr/include/c++/8/bits/streambuf_iterator.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/ctype_inline.h \ + /usr/include/c++/8/bits/locale_facets.tcc \ + /usr/include/c++/8/bits/basic_ios.tcc /usr/include/c++/8/ostream \ + /usr/include/c++/8/bits/ostream.tcc /usr/include/c++/8/bits/istream.tcc \ + /usr/include/c++/8/bits/sstream.tcc /usr/include/unistd.h \ + /usr/include/aarch64-linux-gnu/bits/posix_opt.h \ + /usr/include/aarch64-linux-gnu/bits/environments.h \ + /usr/include/aarch64-linux-gnu/bits/confname.h \ + /usr/include/aarch64-linux-gnu/bits/getopt_posix.h \ + /usr/include/aarch64-linux-gnu/bits/getopt_core.h DevUtil.h \ + /usr/include/c++/8/fstream /usr/include/c++/8/bits/codecvt.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/basic_file.h \ + /usr/include/aarch64-linux-gnu/c++/8/bits/c++io.h \ + /usr/include/c++/8/bits/fstream.tcc /usr/include/c++/8/memory \ + /usr/include/c++/8/bits/stl_construct.h \ + /usr/include/c++/8/bits/stl_uninitialized.h \ + /usr/include/c++/8/bits/stl_tempbuf.h \ + /usr/include/c++/8/bits/stl_raw_storage_iter.h \ + /usr/include/c++/8/ext/concurrence.h \ + /usr/include/c++/8/bits/uses_allocator.h \ + /usr/include/c++/8/bits/unique_ptr.h /usr/include/c++/8/utility \ + /usr/include/c++/8/bits/stl_relops.h /usr/include/c++/8/tuple \ + /usr/include/c++/8/array /usr/include/c++/8/bits/invoke.h \ + /usr/include/c++/8/bits/shared_ptr.h \ + /usr/include/c++/8/bits/shared_ptr_base.h \ + /usr/include/c++/8/bits/allocated_ptr.h \ + /usr/include/c++/8/bits/refwrap.h \ + /usr/include/c++/8/ext/aligned_buffer.h \ + /usr/include/c++/8/bits/shared_ptr_atomic.h \ + /usr/include/c++/8/bits/atomic_base.h \ + /usr/include/c++/8/bits/atomic_lockfree_defines.h \ + /usr/include/c++/8/backward/auto_ptr.h filetools.h \ + /usr/include/c++/8/vector /usr/include/c++/8/bits/stl_vector.h \ + /usr/include/c++/8/bits/stl_bvector.h /usr/include/c++/8/bits/vector.tcc \ + /usr/include/c++/8/chrono /usr/include/c++/8/ratio \ + /usr/include/c++/8/limits /usr/include/c++/8/ctime \ + /usr/include/c++/8/bits/parse_numbers.h Gpio.h Lcd.h \ + /usr/include/aarch64-linux-gnu/sys/stat.h \ + /usr/include/aarch64-linux-gnu/bits/stat.h \ + /usr/include/aarch64-linux-gnu/bits/statx.h /usr/include/fcntl.h \ + /usr/include/aarch64-linux-gnu/bits/fcntl.h \ + /usr/include/aarch64-linux-gnu/bits/fcntl-linux.h \ + /usr/include/aarch64-linux-gnu/bits/types/struct_iovec.h \ + /usr/include/linux/falloc.h diff --git a/device/gxx-linux/motor_run/DevUtil.cpp b/device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.cpp similarity index 79% rename from device/gxx-linux/motor_run/DevUtil.cpp rename to device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.cpp index 310aca3..6b2ab23 100644 --- a/device/gxx-linux/motor_run/DevUtil.cpp +++ b/device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.cpp @@ -1,8 +1,12 @@ #include "DevUtil.h" #include -#define IOEXPORTPATH "/sys/class/gpio/export" -#define PWMEXPORTPATH "/sys/class/pwm/pwmchip%d/export" +#include +#include +#include +#include +#include + int read_dev_i(std::string path) { int val = -1; std::ifstream ifin(path.c_str()); @@ -26,5 +30,5 @@ DeviceExport::DeviceExport() num = sizeof(pwms) / sizeof(pwms[0]); for (int i = 0; i < num; i++) write_dev(string_format(PWMEXPORTPATH, pwms[i]), 0); - printf("DeviceExport::DeviceExport().\n"); } + diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.h b/device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.h new file mode 100644 index 0000000..7c250de --- /dev/null +++ b/device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.h @@ -0,0 +1,99 @@ +#pragma once +#include +#include +#include + +#define IOEXPORTPATH "/sys/class/gpio/export" +#define PWMEXPORTPATH "/sys/class/pwm/pwmchip%d/export" + +template +std::string string_format(const std::string& format, Args ... args) { + size_t size = snprintf(nullptr, 0, format.c_str(), args ...) + 1; + std::unique_ptr buf(new char[size]); + snprintf(buf.get(), size, format.c_str(), args ...); + return std::string(buf.get(), buf.get() + size - 1); +} + +template +void write_dev(std::string path, T value) { + std::ofstream ofout(path); + ofout << value; +} + +extern int read_dev_i(std::string path); + +extern std::string read_dev_s(std::string path); + +enum PORTS +{ + Start = 171, + Stop = 49, + Power = 5, + Fpga_Load = 8, + +#ifndef G300 + Power_12v_Off = 12, +#endif + + MotorPower = 48, + CuoZhiMotor_Reset = 56, + CuoZhiMotor_Sleep = 57, + CuoZhiMotor_Enable = 58, + + CuoZhiMotor_Direction = 62, + CuoZhiMotor_Decay = 63, + CuoZhiMotor_Home = 184, + CuoZhiMotor_Fault = 185, + + CuoZhiMotor_Mode0 = 59, + CuoZhiMotor_Mode1 = 60, + CuoZhiMotor_Mode2 = 61, + Cover = 189,// 'GPIO6A5' opened:0 ; closed:1 + + Paper = 225,// 'GPIO7B1' has paper:0 ; no paper:1 + Scan = 226,// 'GPIO7B2' no paper:0 ; has paper:1 + Scan1 = 102, + Double_Paper = 219,// 'GPIO7A3' not doubled:0 ; doubled:1 + Double_Enable = 250,// 'GPIO8A2' off: 0 ; on: 1 + + ZouZhiMotor_Reset = 64, + ZouZhiMotor_Sleep = 65, + ZouZhiMotor_Enable = 66, + ZouZhiMotor_Direction = 70, + + ZouZhiMotor_Decay = 71, + ZouZhiMotor_Home = 187, + ZouZhiMotor_Fault = 188, + ZouZhiMotor_Mode0 = 67, + + ZouZhiMotor_Mode1 = 68, + ZouZhiMotor_Mode2 = 69, + CIS_3v3_Off = 96, + CIS_5v_En = 98, + + Fpga_InitDone = 99, + Image_In_Transfer = 101, + Fpga_Reset = 232 +}; + +class DeviceExport { +public: + DeviceExport(); +private: +#ifndef G300 + const int ports[37] = { Start , Stop, Power, Fpga_Load, Power_12v_Off, MotorPower, CuoZhiMotor_Reset, CuoZhiMotor_Sleep, CuoZhiMotor_Enable, + CuoZhiMotor_Direction, CuoZhiMotor_Decay, CuoZhiMotor_Home, CuoZhiMotor_Fault , CuoZhiMotor_Mode0 , + CuoZhiMotor_Mode1, CuoZhiMotor_Mode2, Cover, Paper, Scan, Scan1,Double_Paper, Double_Enable, + ZouZhiMotor_Reset, ZouZhiMotor_Sleep, ZouZhiMotor_Enable, ZouZhiMotor_Direction, ZouZhiMotor_Decay, + ZouZhiMotor_Home, ZouZhiMotor_Fault, ZouZhiMotor_Mode0, ZouZhiMotor_Mode1, ZouZhiMotor_Mode2, + CIS_3v3_Off, CIS_5v_En, Fpga_InitDone, Image_In_Transfer, Fpga_Reset }; +#else + const int ports[36] = { Start , Stop, Power, Fpga_Load, MotorPower, CuoZhiMotor_Reset, CuoZhiMotor_Sleep, CuoZhiMotor_Enable, + CuoZhiMotor_Direction, CuoZhiMotor_Decay, CuoZhiMotor_Home, CuoZhiMotor_Fault , CuoZhiMotor_Mode0 , + CuoZhiMotor_Mode1, CuoZhiMotor_Mode2, Cover, Paper, Scan, Scan1, Double_Paper, Double_Enable, + ZouZhiMotor_Reset, ZouZhiMotor_Sleep, ZouZhiMotor_Enable, ZouZhiMotor_Direction, ZouZhiMotor_Decay, + ZouZhiMotor_Home, ZouZhiMotor_Fault, ZouZhiMotor_Mode0, ZouZhiMotor_Mode1, ZouZhiMotor_Mode2, + CIS_3v3_Off, CIS_5v_En, Fpga_InitDone, Image_In_Transfer, Fpga_Reset }; +#endif + const int pwms[2] = { 0, 1 }; +}; \ No newline at end of file diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.o b/device/gxx-linux/small_lcd/app_spi_lcd/DevUtil.o new file mode 100644 index 0000000000000000000000000000000000000000..578ec76ea667a2863704ff35d6479cac63110203 GIT binary patch literal 30456 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 +// +// Created by yingluo907 on 2019/4/11. +// #include "Gpio.h" #include "DevUtil.h" +#include +#include +#include +#include +#include #define IOPATH "%s/gpio%d/%s" @@ -19,12 +26,9 @@ Gpio::Gpio(int port) path_edge = string_format(IOPATH, path_gpiobase.c_str(), port, path_edge.c_str()); path_direction = string_format(IOPATH, path_gpiobase.c_str(), port, path_direction.c_str()); path_active_low = string_format(IOPATH, path_gpiobase.c_str(), port, path_active_low.c_str()); - printf("Gpio::Gpio(int port = %d) \n",port); -} - -Gpio::~Gpio() -{ - std::cout << "Gpio::~Gpio()" << std::endl; + sprintf (fname, "/sys/class/gpio/gpio%d/value", port); + gpio_fd = open (fname, O_RDWR); + printf("Gpio::gpio%d.fd = %d.\n",port,gpio_fd); } int Gpio::getPort() @@ -34,7 +38,13 @@ int Gpio::getPort() void Gpio::setValue(GpioLevel level) { - write_dev(path_value, level); + //write_dev(path_value, level); + if(port == 153 || port == 150) + printf("\n Gpio %d setvalue %d ",port,level==Low?0:1); + if (level == Low) + write (gpio_fd, "0\n", 2); + else + write (gpio_fd, "1\n", 2); } Gpio::GpioLevel Gpio::getValue() { @@ -48,6 +58,8 @@ std::string Gpio::getDirection() void Gpio::setDirection(std::string direction) { + if(port == 153 || port == 150) + printf("\n Gpio %d setDirection %s ",port,direction.c_str()); write_dev(path_direction, direction); } @@ -71,9 +83,8 @@ std::string Gpio::getEdge() return read_dev_s(path_edge); } -GpioOut::GpioOut(int port) : Gpio(port) +GpioOut::GpioOut(int port) : + Gpio(port) { setDirection(out); } - - diff --git a/device/gxx-linux/motor_run/Gpio.h b/device/gxx-linux/small_lcd/app_spi_lcd/Gpio.h similarity index 84% rename from device/gxx-linux/motor_run/Gpio.h rename to device/gxx-linux/small_lcd/app_spi_lcd/Gpio.h index ba785c5..a1c820c 100644 --- a/device/gxx-linux/motor_run/Gpio.h +++ b/device/gxx-linux/small_lcd/app_spi_lcd/Gpio.h @@ -1,4 +1,9 @@ -#pragma once +// +// Created by yingluo907 on 2019/4/11. +// + +#ifndef HGSCANSERVICE_GPIO_H +#define HGSCANSERVICE_GPIO_H #include class Gpio { @@ -7,18 +12,17 @@ public: Low, High }; - public: static const std::string falling; static const std::string rising; static const std::string both; static const std::string none; + static const std::string in; static const std::string out; public: Gpio(int port); - ~Gpio(); int getPort(); void setValue(GpioLevel level); GpioLevel getValue(); @@ -40,8 +44,8 @@ private: std::string path_edge = "edge"; std::string path_direction = "direction"; std::string path_active_low = "active_low"; - - + int gpio_fd; + char fname[128]; }; class GpioOut : public Gpio @@ -51,3 +55,4 @@ public: }; +#endif //HGSCANSERVICE_GPIO_H diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/Gpio.o b/device/gxx-linux/small_lcd/app_spi_lcd/Gpio.o new file mode 100644 index 0000000000000000000000000000000000000000..9a4bef193a4ae867f60477f47b45abe5ee1148ab GIT binary patch literal 41344 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 //设置列地址的高4位 + Lcd_Transfer_Command(column&0x0f); //设置列地址的低4位 +} + +/*全屏清屏*/ +/*void Lcd::Lcd_Clear_screen() +{ + //COM_BOOT0.setValue(Gpio::Low); + unsigned char i,j; + spi_cs.setValue(Gpio::Low); + for(i=0;i<9;i++) + { + Lcd_Address(1+i,1); + for(j=0;j<132;j++) + { + Lcd_Transfer_data(0x00); + } + } + spi_cs.setValue(Gpio::High); +}*/ +void Lcd::Lcd_Clear_screen() +{ + unsigned char i,j; + //spi_cs.setValue(Gpio::Low); + for(i=0; i<4; i++) + { + Lcd_Transfer_Command(0xb0+i); + Lcd_Transfer_Command(0x10); + Lcd_Transfer_Command(0x00); + for(j = 0;j<132;j++) + { + Lcd_Transfer_data(0x00); + } + + } +} + + +//===显示测试画面:例如全显示,隔行显示,隔列显示,雪花显示===== +void Lcd::Lcd_Test_Display(unsigned char data1, unsigned char data2) +{ + int i,j; + for(j=0;j<8;j++) + { + spi_cs.setValue(Gpio::Low); + Lcd_Address(j+1,1); + for(i=0;i<128;i++) + { + Lcd_Transfer_data(data1); + Lcd_Transfer_data(data2); + } + } +} + +/*显示128x64点阵图像*/ +void Lcd::Lcd_Display_Graphic_128x64(unsigned char page, unsigned char column, unsigned char *dp) +{ + int i,j; + for(j=0;j<8;j++) + { + spi_cs.setValue(Gpio::Low); + Lcd_Address(page+j,column); + for(i=0;i<128;i++) + { + Lcd_Transfer_data(*dp); + dp++; + } + } +} + +/*显示32x32点阵图像、汉字、生僻字或32x32点阵的其他图标*/ +void Lcd::Lcd_Display_graphic_32x32(unsigned char page, unsigned char column, unsigned char *dp) +{ + unsigned char i,j; + spi_cs.setValue(Gpio::Low); + for(j=0;j<4;j++) + { + Lcd_Address(page+j,column); + for (i=0;i<31;i++) + { + Lcd_Transfer_data(*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + dp++; + } + } +} + + +/*显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标*/ +void Lcd::Lcd_Display_Graphic_16x16_2(unsigned char reverse,unsigned char page,unsigned char column,unsigned char *dp) +{ + unsigned char i,j; + + spi_cs.setValue(Gpio::Low); + for(j=0;j<2;j++) + { + Lcd_Address(page+j,column); + for (i=0;i<16;i++) + { + if(reverse==1) + Lcd_Transfer_data(*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + else + Lcd_Transfer_data(~*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + dp++; + } + } + spi_cs.setValue(Gpio::High); +} + +/*显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标*/ +void Lcd::Lcd_Display_Graphic_16x16(unsigned char page, unsigned char column, unsigned char *dp, unsigned int wordcount) +{ + unsigned char i,j,k; + spi_cs.setValue(Gpio::Low); + for (k = 0; k < wordcount; k++) + { + for(j=0;j<2;j++) + { + Lcd_Address(page+j,column+16 * k); + for (i=0;i<16;i++) + { + Lcd_Transfer_data(*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + dp++; + } + } + } + spi_cs.setValue(Gpio::High); + +} + +/*显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标*/ +void Lcd::Lcd_Display_Graphic_8x16(unsigned char page, unsigned char column,unsigned char *dp) +{ + unsigned char i,j; + spi_cs.setValue(Gpio::Low); + for(j=0;j<2;j++) + { + Lcd_Address(page+j,column); + for (i=0;i<8;i++) + { + Lcd_Transfer_data(*dp); /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/ + dp++; + } + } + spi_cs.setValue(Gpio::High); +} + +/*void Lcd::Lcd_Display_String_8x16(unsigned int page, unsigned int column, const char *text) +{ + unsigned int i=0,j,k,n; + //COM_BOOT0.setValue(Gpio::Low); + spi_cs.setValue(Gpio::Low); + while(text[i]>0x00) + { + if((text[i]>=0x20)&&(text[i]<=0x7e)) + { + j=text[i]-0x20; + for(n=0;n<2;n++) + { + Lcd_Address(page+n,column); + for(k=0;k<8;k++) + { + Lcd_Transfer_data(ascii_table_8x16[j][k+8*n]);//显示5x7的ASCII字到LCD上,y为页地址,x为列地址,最后为数据 + } + } + i++; + column+=8; + + } + else + i++; + } +} +*/ +/*void Lcd::Lcd_Display_String_5x8(unsigned int page, unsigned int column, const char *text) +{ + unsigned int i=0,j,k; + spi_cs.setValue(Gpio::Low); + while(text[i]>0x00) + { + if((text[i]>=0x20)&&(text[i]<0x7e)) + { + j=text[i]-0x20; + Lcd_Address(page,column); + for(k=0;k<5;k++) + { + Lcd_Transfer_data(ascii_table_5x8[j][k]);//显示5x7的ASCII字到LCD上,y为页地址,x为列地址,最后为数据 + } + i++; + column+=6; + } + else + i++; + } +} +*/ +void Lcd::display_Selective(int selective) +{ + COM_BOOT0.setValue(Gpio::Low); + switch(selective) + { + case 1: + Lcd_Display_Graphic_16x16(1, 1, Downloading, 5); + Lcd_Display_Graphic_16x16(3, 1, Downloading, 5); + break; + case 2: + Lcd_Display_Graphic_16x16(1, 1, downloadSuccess, 5); + Lcd_Display_Graphic_16x16(3, 1, downloadSuccess, 5); + break; + case 3: + Lcd_Display_Graphic_16x16(1, 1, downloadFailure, 5); + Lcd_Display_Graphic_16x16(3, 1, downloadFailure, 5); + break; + case 4: + Lcd_Display_Graphic_16x16(1, 1, ChooseAgain, 5); + Lcd_Display_Graphic_16x16(3, 1, ChooseAgain, 5); + break; + default: + printf("selective display is erro!\n"); + break; + } +} diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/Lcd.h b/device/gxx-linux/small_lcd/app_spi_lcd/Lcd.h new file mode 100644 index 0000000..2013960 --- /dev/null +++ b/device/gxx-linux/small_lcd/app_spi_lcd/Lcd.h @@ -0,0 +1,73 @@ +#ifndef HGSCANSERVICE_LCD_H +#define HGSCANSERVICE_LCD_H + +#include +#include +#include +#include +#include +#include "DevUtil.h" +#include "filetools.h" +#include "Gpio.h" +#include +#include +#include + + +class Lcd +{ +private: + Gpio spi_sck; + Gpio spi_sda; + Gpio spi_cs; + Gpio spi_reset; + Gpio spi_rs; + Gpio COM_BOOT0; + +public: + Lcd(); + /*=======写指令========*/ + void Lcd_Transfer_Command(int data1); + + /*--------写数据------------*/ + void Lcd_Transfer_data(int data1); + + /*大LCD模块初始化*/ + void Small_Lcd_Initial_Lcd(); + + void Big_Lcd_Initial_Lcd(); + + void Lcd_Address(unsigned char page, unsigned char column); + + /*全屏清屏*/ + void Lcd_Clear_screen(); + + //===显示测试画面:例如全显示,隔行显示,隔列显示,雪花显示===== + void Lcd_Test_Display(unsigned char data1, unsigned char data2); + + /*显示128x64点阵图像*/ + void Lcd_Display_Graphic_128x64(unsigned char page, unsigned char column, unsigned char *dp); + + /*显示32x32点阵图像、汉字、生僻字或32x32点阵的其他图标*/ + void Lcd_Display_graphic_32x32(unsigned char page, unsigned char column, unsigned char *dp); + + /*显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标*/ + void Lcd_Display_Graphic_16x16_2(unsigned char reverse,unsigned char page,unsigned char column,unsigned char *dp); + + /*显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标*/ + void Lcd_Display_Graphic_16x16(unsigned char page, unsigned char column, unsigned char *dp, unsigned int wordcount); + + /*显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标*/ + void Lcd_Display_Graphic_8x16(unsigned char page, unsigned char column,unsigned char *dp); + + void Lcd_Display_String_8x16(unsigned int page, unsigned int column, const char *text); + + void Lcd_Display_String_5x8(unsigned int page, unsigned int column, const char *text); + + void display_Selective(int selective); + +}; + +#endif + + diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/Lcd.o b/device/gxx-linux/small_lcd/app_spi_lcd/Lcd.o new file mode 100644 index 0000000000000000000000000000000000000000..46e970052dd5c08a509d24fbb58b8d04250062f0 GIT binary patch literal 28720 zcmdU1e{fXCec#hN;AG2i25e(PtV75~wz1F&0m8xd6Ve6A)?gXQF?C2D$LWyHK6K*l z1j0}wj3-r7CKa)oFb&3PL#ImWwoJw|feDG_m^5UPnUaJi{DD0u@E_`o+mblbKw_+Z zzq{Xk_q})Tfn<9!>CW8S-Oql1?RS5_x6-~y>t{-QKB0q8d`IMS8Wp0~%BM}4G)1FW zCu#45Jo4N{@j{3fQTkI9-wkm&r9%)ergR0wODJ6l@jaAY3UL*s?}PY$N)hh;Lpq#G&_Z7FTn3;Lp4o zojI@(iia^R#{7qTr7S;CdZ=L@%bT+gy*ZcV#k@oNdHL8KhZa*FWDddakd)nM*zu*e zN)BB##J8{<{CX&77?>W;0dCs@=>on>#1HYMnBmS3xNSS6B|p&1_<-MzFByJ!e!%Uz zLb`x&$qbc;_|i8#_yMx`Q9Rah%YtHaMusG?Mp~YexR3eY^EJwy5zwRxb}Sx z(wy&oXxobiqzv%6c{OL0D4zp14sDS$=Gl442lVrxFI+Tcp`1b}LtP8

+H<*jSJU{XUY{CB*#q(eKpHOLV?b_1ASePyN^~r~V9MTJcjqwaX8v zeg|`dDyM#EmoHKM;(lG;sPcCCTPk0n%c&pP<!YWpBlbh=czBu)p=^?**Z^c zc$3bnHXNR*^W=M5pPZBKkbSuT1K(mlEx^G4MHsYE5eDs8gyH-{W8nRp&8ye;nBRo? z^3a%J{c`ev_*rg_I5}A^PL7wGCv$VmlaC7V+_!w9V{)N5nOkU{EPvg%<24~VFfIJz z)*Rr!pPalS2lO%zyuXHgdC2$=kXIxZ>BdQJ?pLqg1q;kvSWkA0piCy?e?f+=6UuWx za?mpUzjNrjw�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 literal 0 HcmV?d00001 diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/Makefile b/device/gxx-linux/small_lcd/app_spi_lcd/Makefile new file mode 100644 index 0000000..f720840 --- /dev/null +++ b/device/gxx-linux/small_lcd/app_spi_lcd/Makefile @@ -0,0 +1,22 @@ +objs := main.o Lcd.o DevUtil.o Gpio.o + +smalllcd : $(objs) + g++ -o $@ $^ -lpthread + +# 需要判断是否存在依赖文件 +dep_files := $(foreach f, $(objs), .$(f).d) +dep_files := $(wildcard $(dep_files)) + +# 把依赖文件包含进来 +ifneq ($(dep_files),) + include $(dep_files) +endif + +%.o : %.cpp + g++ -Wp,-MD,.$@.d -c -o $@ $< -lpthread + +clean: + rm *.o biglcd -f + +distclean: + rm $(dep_files) *.o biglcd -f \ No newline at end of file diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/Parameters.h b/device/gxx-linux/small_lcd/app_spi_lcd/Parameters.h new file mode 100644 index 0000000..31e5cce --- /dev/null +++ b/device/gxx-linux/small_lcd/app_spi_lcd/Parameters.h @@ -0,0 +1,102 @@ +#pragma once +#include + +#define Color 3 + +typedef enum Scan_Mode +{ + SM_GRAY, + SM_COLOR +} ScanMode; + +const std::string ScanPaperTypes[] = +{ + + "A4", + "A3" +}; + +const int SPTSizes[] = {1728, 1632}; + +typedef enum Scan_Paper_Type +{ + SPT_A4, + SPT_A3 +}ScanPaperType; + +#ifdef A3 + + // 图像像素值 + #define IMG_HEIGHT 3600 + #define IMG_WIDTH 2592 * 2 + #define SPI_COLOR 0x04501003 //0x0cf01002, 0x04501003 + #define SPI_GRAY 0x0cf01002 + + // 300 dpi 图像宽度像素值(目前仅为双面扫描,故尺寸为单面尺寸乘以2) + #define IMG_WIDTH_300DPI 3672 * 2 + + // 200 dpi 图像宽度像素值(目前仅为双面扫描,故尺寸为单面尺寸乘以2) + #define IMG_WIDTH_200DPI 2448 * 2 + + #define IMG_WIDTH_150DPI 1836 * 2 + + #define IMG_HEIGHT_200DPI IMG_HEIGHT + + #define IMG_HEIGHT_300DPI IMG_HEIGHT * 1.5 + + #define IMG_HEIGHT_150DPI IMG_HEIGHT * 0.75 + + //原始图像相对于200dpi的倍数 + #define IMG_W_RADIO 1 + #define IMG_H_RADIO 1 + #define FRAME_COUNT 4 + + +#else + // 300 dpi 图像宽度像素值(目前仅为双面扫描,故尺寸为单面尺寸乘以2) + +#define IMG_WIDTH_300DPI 2592 * 2 + + // 200 dpi 图像宽度像素值(目前仅为双面扫描,故尺寸为单面尺寸乘以2) +#define IMG_WIDTH_200DPI 1728 * 2 + +#define IMG_WIDTH_150DPI 1296 * 2 + + +#define IMG_HEIGHT_200DPI 3600 + +#define IMG_HEIGHT_300DPI 4050 + +#define IMG_HEIGHT_150DPI 2025 + + //原始图像相对于200dpi 系数 +#define IMG_W_RADIO 1/1.5 +#define IMG_H_RADIO 1 + + // 图像像素值 + + + + +#ifdef HAS_UV +// #define SPI_COLOR 0x03D81001 +// #define SPI_GRAY 0x13001000 + #define SPI_COLOR 0x05181001 + #define SPI_GRAY 0x19501000 +// 0x19501000, 0x05181001 +#else +const int SPI_SP = 0x04b0; +const int SPI_SAMPLE = 256; +const int SPI_COLOR_MODE = SM_COLOR; +const int SCAN_PAPER_TYPE = SPT_A4; +#endif + +const int IMG_HEIGHT = 12000; +const int IMG_V4L_WIDTH = SPTSizes[SCAN_PAPER_TYPE]; +const int FRAME_COUNT = 3; +const int TEST_FRAME = 1; +const int TEST_ENABLE = 0; +const int LED_ENABLE = 1; +const bool SAVE_ENABLE = true; + +#endif diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/filetools.h b/device/gxx-linux/small_lcd/app_spi_lcd/filetools.h new file mode 100644 index 0000000..e9a7c29 --- /dev/null +++ b/device/gxx-linux/small_lcd/app_spi_lcd/filetools.h @@ -0,0 +1,75 @@ +#pragma once +#include +#include +#include +#include +#include + + + +class FileTools +{ +private: + std::string mPath; +public: + FileTools(std::string path){ + mPath = path; + } + void createLog(std::string log) + { + time_t now = time(0); + tm *ltm = localtime(&now); + char loc_date[30]; + sprintf(loc_date, "%d%02d%02d %d:%d:%d", 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday,ltm->tm_hour, ltm->tm_min, ltm->tm_sec); + std::ofstream ofs(mPath); + ofs << loc_date << ": " << log << std::endl; + ofs.close(); + } + void appendLog(std::string log, bool printTime = true) + { + std::ofstream ofs(mPath, std::ios::app); + if(printTime){ + time_t now = time(0); + tm *ltm = localtime(&now); + char loc_date[30]; + sprintf(loc_date, "%d%02d%02d %d:%d:%d", 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday,ltm->tm_hour, ltm->tm_min, ltm->tm_sec); + ofs << loc_date << ": " << log << std::endl; + }else{ + ofs << " " << log << std::endl; + } + ofs.close(); + } +}; + + +class StopWatch +{ +public: + StopWatch() { + _start = std::chrono::steady_clock::now(); + } + + void reset() { + _start = std::chrono::steady_clock::now(); + } + + double elapsed_s() { + return std::chrono::duration(std::chrono::steady_clock::now() - _start).count(); + } + + double elapsed_ms() { + return std::chrono::duration(std::chrono::steady_clock::now() - _start).count(); + } + + double elapsed_us() { + return std::chrono::duration(std::chrono::steady_clock::now() - _start).count(); + } + + double elapsed_ns() { + return std::chrono::duration(std::chrono::steady_clock::now() - _start).count(); + } + +private: + std::chrono::steady_clock::time_point _start; +}; + diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/lcd b/device/gxx-linux/small_lcd/app_spi_lcd/lcd new file mode 100644 index 0000000000000000000000000000000000000000..e5d1bd30fe9be2e78f009f9a825a251a2d4238af GIT binary patch literal 44464 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 +#include +#include +#include +#include +#include "DevUtil.h" +#include "filetools.h" +#include "Gpio.h" +#include "Lcd.h" + +int main(int argc, char **argv) +{ + Lcd Small_lcd; + Small_lcd.Small_Lcd_Initial_Lcd(); + while(1) + { + //Small_lcd.Lcd_Clear_screen(); + Small_lcd.display_Selective(4); + //sleep(2); + //Small_lcd.Lcd_Clear_screen(); + Small_lcd.display_Selective(1); + //sleep(2); + //Small_lcd.Lcd_Clear_screen(); + Small_lcd.display_Selective(2); + //sleep(2); + //Small_lcd.Lcd_Clear_screen(); + Small_lcd.display_Selective(3); + //sleep(2); + //Small_lcd.Lcd_Clear_screen(); + Small_lcd.display_Selective(1); + //sleep(2); + } + return 0; +} + diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/main.o b/device/gxx-linux/small_lcd/app_spi_lcd/main.o new file mode 100644 index 0000000000000000000000000000000000000000..88642cba65686f1a10fb79c71a4404ad87492a9e GIT binary patch literal 4280 zcmbVPPfQ$T6o1R0wH84^3z7cWR;)E?M;5d##+XGwBq0@9QDd5n!|bq3y6mpI16{zR zaPwkfqX(mD!?D(j2NU&ThC6NGW3HThsp0EJ7?hSET!8CNkUS+!*`=lnnJ@~XSZb#XH&(6sHAGTNF z<81>j+}s1Vx1NA6uXmyR1}>obeO<1@+O%+oG(4UwqPOiJ>_e`H`6-ga?a7O+myGG(ex3B01ddi zfg{3zT`~MU4SaB{8~OXtG65kkgFni=Y=y`dnHLYS&oW=z59~`bfGVfHy{Wp5Jkf@# zu4eXBb@eTXBcrR=89=jZYzC-fP^Spir;#Tk10JZerA}bq2@f`C$iB0I^%Wzl6{^=2 zj8<--H)^Llv?pY!Q&i6dd|Vu(!T23y4r}|O>IAtD@sT~$oqme3zpnUjUsOFI_g4&0 zmrAF0&Z&l|{e#b;mT>*$d_9ay)@(dSV)*eGJ{!Z|6~n`V?G;R?RD!-NSg&XN$<$EE za~=1bS8*+;Sg82rMaM_g=^@L?6&5Y0TAdt7SytAavlsKel`lGHtx_@XIm=@lVbIPa zYx~8rWtVdSdBV#Tie(r2sub(V@sd{@eQIopI)jr=R&byg2oxFrq(%8ssno!%UGW?X zN8=T86HdlYrJQ-YZ24u|^D7h1SjNVmvC&lE8HC}Eiq9bxCZ6UEqpzA}ch1C#RjXFX zEmw*KJMa0+)>6L=Y(xt(kjgCJ)GQpYHBs<<&sI2`Me1bMtCaHgvXyc3uH$=4?wAMG zOyQhY$Xe5GWpTk($3Wf9gnDsb9tkM*+sBxA!9?|I{G*IXJQKse5W~M5!@m*3moz@f zm_(H^jq`}c%RNE-evMCR_BwwohL`tNG)_9kUe9}gZAc^;QyiVw^Xj~wSLa7#;!MWy zOapz2JtiHL`xsL_hPO$$kHqV@c}}xGti_S_Cwu)iT-WUD?h~`Jyx`ljU}6aca$Zo` z&D*B$R(&wDwr_(uTd9CqE(V>N)~wYn)e;sCdl6qNF*D~lmRoh)l5b&}yvv3Zi(E{) z81m+S6`tu77Z%(Cj;2ubU32{O%<+nEJ7+nPJ8#XEZLA|RS1vBf`P7!?j^K~z)%f-U zNOLs$2Bt>mY%f0YCKegzFXuz|@BSbDuc0k9-Ji~Z(E!IZ`+3M{Wb|~hZ`lryBV(PVkUD%=@ zY|*`y@dsLfXA!9Niv;+a4W`79rL4QqLkQIRMf}$|k<=@#AAJoh%`Q{}L*j<-f&=-eqUXPxnqV|2%Td)^CIJ*WD#-i=x)fBO+5HGXGE6U-F4Vw7-Ii zX5)XGKb>WrX#Di`B>uvGf*hsl$475paDM%rLwcrb@-vOo{jZ9lPByXqj=9M6;TrpY z5b>As3;ituHGd&kZt(o8+^6}|SGV}f{3%T|H@TFU+~mS~2swHOMg1vFwDypKe*Q~V YiL67UtLm$ne^2lS0)C-jT8sMs3+OVIrvLx| literal 0 HcmV?d00001 diff --git a/device/gxx-linux/small_lcd/app_spi_lcd/smalllcd b/device/gxx-linux/small_lcd/app_spi_lcd/smalllcd new file mode 100644 index 0000000000000000000000000000000000000000..b5f327d00afc6d0922d2efe17b3e3494775dccbb GIT binary patch literal 50080 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 i^>_1U6 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VIDPID_PATH "/opt/camtprd-ffs.sh" - -/* - * FunctionName: main - * Description: - */ -int main(int argc, char *argv[]) -{ - int ret = 0; - printf("argc = %d \n", argc); - if (argc != 3) - { - return -1; - } - unsigned int i_vid = atoi(argv[1]); - unsigned int i_pid = atoi(argv[2]); - printf("arg0 = %d arg1=%d \n", i_vid, i_pid); - char buf_vid[5] ={0}; - char buf_pid[5] ={0}; - buf_vid[4]='\0'; - buf_pid[4]='\0'; - sprintf(buf_vid,"%04x",i_vid); - sprintf(buf_pid,"%04x",i_pid); - printf("buf_vid = %s buf_pid=%s \n", buf_vid, buf_pid); - if (i_pid > 0 && i_vid > 0) - { - FILE *fd; - - fd = fopen(VIDPID_PATH, "rb+"); - if (!fd) { - printf( "error open /usr/local/bin/mtp.sh...\n"); - return -1; - } - else { - printf( "open %s scuess.fd = %d\n", VIDPID_PATH,fd); - } - - /*set vid*/ - fseek(fd , 0x1cb , SEEK_SET); - ret = fwrite(buf_vid, 1, 4, fd); - - /*set pid*/ - fseek(fd , 0x1b3 , SEEK_SET); - ret = fwrite(buf_pid, 1, 4, fd); - - fclose(fd); - return 0; - } - - return -1; -} /* ---------- end of function main ---------- */ diff --git a/device/gxx-linux/testcapimage/main.cpp b/device/gxx-linux/testcapimage/main.cpp index b92c5a3..14056f3 100644 --- a/device/gxx-linux/testcapimage/main.cpp +++ b/device/gxx-linux/testcapimage/main.cpp @@ -8,6 +8,9 @@ #include "config.h" #include "FpgaComm.h" #include "usbservice.h" +#include "MonoCapturer.h" +#include "correct_ultis.h" +#define LOOP_DEBUG static void savebitmap(void *imgdata, int width, int height, bool color, std::string path) { @@ -32,7 +35,7 @@ static void savebitmap(void *imgdata, int width, int height, bool color, std::st std::cout << string_format("split: %d image elapsed:%f ms\n ", i, sw.elapsed_ms()); sw.reset(); - + // if(i == 0) // { // swap(ch_mats[0], ch_mats[2]); @@ -45,7 +48,6 @@ static void savebitmap(void *imgdata, int width, int height, bool color, std::st // swap(ch_mats[1], ch_mats[0]); // } - if (i == 2) { swap(ch_mats[0], ch_mats[2]); @@ -56,7 +58,6 @@ static void savebitmap(void *imgdata, int width, int height, bool color, std::st swap(ch_mats[0], ch_mats[2]); } - cv::merge(ch_mats, saveMat(cv::Rect(mergewidth * i, 0, mergewidth, height))); std::cout << string_format("merge: %d image elapsed:%f ms\n ", i, sw.elapsed_ms()); ch_mats.clear(); @@ -70,32 +71,34 @@ unsigned int delay_done(std::shared_ptr regs, int ms) unsigned int val; unsigned int reg8; regs->read(8, reg8); - std::cout << "reg[8]:" << string_format("0x%08x", reg8) << std::endl; + std::cout << "1 reg[8]:" << string_format("0x%08x", reg8) << std::endl; regs->write(8, reg8 | 0x8); std::cout << "sleep:" << ms << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(ms)); regs->read(8, reg8); - std::cout << "reg[8]:" << string_format("0x%08x", reg8) << std::endl; + std::cout << "1 reg[8]:" << string_format("0x%08x", reg8) << std::endl; regs->read(14, val); + int regv = val; val &= 0x0000ffff; - std::cout << string_format("leight = %d\n", val); + std::cout << string_format("ONE height = %d reg[14] = %d \n", val, regv); regs->write(8, reg8 & 0xfffffff7); std::this_thread::sleep_for(std::chrono::milliseconds(5)); regs->read(14, val); + regv = val; val &= 0x0000ffff; regs->read(8, reg8); - std::cout << "reg[8]:" << string_format("0x%08x", reg8) << std::endl; + std::cout << "2 reg[8]:" << string_format("0x%08x", reg8) << std::endl; + std::cout << string_format("TWO height = %d reg[14] = %d \n", val, regv); std::this_thread::sleep_for(std::chrono::milliseconds(5)); regs->write(8, reg8 | 0x8); regs->read(8, reg8); - std::cout << "reg[8]:" << string_format("0x%08x", reg8) << std::endl; + std::cout << "2 reg[8]:" << string_format("0x%08x", reg8) << std::endl; return val; } -int delaytimes[] = {100, 200, 300, 400}; - -int ws[] = {7344/2, 7344}; +int delaytimes[] = {200, 300, 400, 100, 150}; +int ws[] = {7344 / 2, 7344}; void list_regs(std::shared_ptr regs) { @@ -109,104 +112,217 @@ void list_regs(std::shared_ptr regs) } } +// int main() +// { +// auto cap = std::shared_ptr(new MonoCapturer()); +// StopWatch sw; +// unsigned int val = 0; +// +// auto regs = cap->regs(); +// // UsbService us(regs, nullptr); +// HGScanConfig config; +// config.g200params.color = 0; +// config.g200params.dpi = 3; +// config.g200params.paper = (unsigned int)PaperSize::G400_AUTO; +// void *data; +// // cap->init_autocorrect(0); +// cap->open(config); +// int ch = 0; +// int ixx = 0; +// +// // std::cout << "mod1:" << CV_8UC3 << " " << CV_8UC1 << std::endl; +// +// for (int i = 0; i < 0x10; i++) +// { +// sw.reset(); +// if (regs->read(i, val)) +// std::cout << string_format("reg[%d] = 0x%08x\n", i, val); +// else +// std::cout << "read regs error " << std::endl; +// } +// std::cout << "type enter to grab" << std::endl; +// int ix = 0; +// int width = cap->width(); +// int fixedheight = cap->height(); +// int type = cap->color(); +// int height = fixedheight; +// if (type == CV_8UC3) +// { +// height = fixedheight / 3; +// width = width * 2 * 3 * 3; +// type = CV_8UC1; +// } +// else +// { +// height = fixedheight; +// width = width * 2 * 3; +// } +// +// while ((ch = getchar()) != 'q') +// { +// #ifdef LOOP_DEBUG +// for (int i = 0; i < 2000; i++) +// #endif +// { +// ix++; +// // sw.reset(); +// // for (int j = 0; j < 15; j++) +// // { +// // sw.reset(); +// // if (regs->read(j, val)) +// // std::cout << string_format("reg[%d] = 0x%08x, %f\n", j, val, sw.elapsed_ms()); +// // else +// // std::cout << "read regs error " << std::endl; +// // } +// sw.reset(); +// cap->snap(); +// +// #ifdef LOOP_DEBUG +// height = delay_done(regs, delaytimes[ix % (sizeof(delaytimes) / sizeof(delaytimes[0]))]); +// std::cout << string_format("%dth grab time height = %d", ix, height) << std::endl; +// height = std::min(fixedheight, height); +// #endif +// if (data = cap->readFrame(5000)) +// { +// // for (int i = 0; i < 0x10; i++) +// // { +// // sw.reset(); +// // if (regs->read(i, val)) +// // std::cout << string_format("readFrame reg[%d] = 0x%08x\n", i, val); +// // else +// // std::cout << "read regs error " << std::endl; +// // } +// // std::cout << string_format("QQQQQQQQ %dth grab time height = %d: %fms", ix, height, sw.elapsed_ms()) << std::endl; +// std::cout << string_format("grab time width = %d, height = %d, type = %d: %fms", width, height, type, sw.elapsed_ms()) << std::endl; +// sw.reset(); +// int channel = cap->color() == 16 ? 3 : 1; +// int dstwith = cap->width() * 2 * 3; +// int dstHeight = height; +// cv::Mat mat(dstHeight, dstwith * channel, CV_8UC1, data); +// static int testindex = 0; +// cv::imwrite(std::to_string(++testindex) + std::to_string(dstHeight) + "autosizeorg.jpg", mat); +// #ifndef LOOP_DEBUG +// // cv::Mat mat=GetMergeMat(data,cap->width(),cap->height(),cap->color()); +// // mat = cv::Mat(height, width, type, data); +// // cv::imwrite( std::to_string(ix++)+ ".jpg", mat); +// // std::cout << string_format("%dth grab time height = %d: %fms", ix, height, sw.elapsed_ms()) << std::endl; +// // sw.reset(); +// // savebitmap(data, width, height, true, std::to_string(ix) + ".jpg"); +// // std::cout << string_format("%dth grab save time : %fms", ix, sw.elapsed_ms()) << std::endl; +// // sw.reset(); +// // memset(data, 0, width * height * 3); +// // std::cout << string_format("%dth memset time : %fms", ix, sw.elapsed_ms()) << std::endl; +// #endif +// break; +// } +// else +// { +// std::cout << "error :" << ix << std::endl; +// #ifdef LOOP_DEBUG +// break; +// #endif +// } +// } +// std::cout << "type enter to continue" << std::endl; +// } +// +// return 0; +// } + int main() { - auto cap = std::shared_ptr(new Capturer()); + auto cap = std::shared_ptr(new MonoCapturer()); StopWatch sw; unsigned int val = 0; - auto regs = cap->regs(); - UsbService us(regs, nullptr); - HGScanConfig config; - config.g200params.color=1; - config.g200params.dpi=1; - config.g200params.paper=(unsigned int)PaperSize::G400_A4; - void *data; - // cap->open(config); - cap->open(); - int ch = 0; - int ixx = 0; - - std::cout << "mod1:" << CV_8UC3 << " " << CV_8UC1 << std::endl; - - - for (int i = 0; i < 0x10; i++) - { - sw.reset(); - if (regs->read(i, val)) - std::cout << string_format("reg[%d] = 0x%08x\n", i, val); - else - std::cout << "read regs error " << std::endl; - } - std::cout << "type enter to grab" << std::endl; - int ix = 0; - // int width = cap->width();; - // int fixedheight = cap->height() ; - // int type = cap->color(); - // int height = fixedheight; - // if(type == CV_8UC3) - // { - // height = fixedheight/3; - // width = width*3*3; - // type = CV_8UC1; - // } - // else - // { - // height = fixedheight; - // width = width*3; - // } - - - while ((ch = getchar()) != 'q') + auto regs = cap->regs(); + // UsbService us(regs, nullptr) + int looptimes = 0; + // while ((ch = getchar()) != 'q') { #ifdef LOOP_DEBUG - for (int i = 0; i < 2000; i++) + for (;;) #endif { - ix++; - sw.reset(); - for (int j = 0; j < 15; j++) - { - sw.reset(); - if (regs->read(j, val)) - std::cout << string_format("reg[%d] = 0x%08x, %f\n", j, val, sw.elapsed_ms()); - else - std::cout << "read regs error " << std::endl; - } - cap->snap(); + HGScanConfig config; + config.g200params.color = 0; + config.g200params.dpi = 2; + config.g200params.paper = (unsigned int)PaperSize::G400_AUTO; + void *data; + // cap->init_autocorrect(0); + FPGAConfigParam fpgaparam = GetFpgaparam(config.g200params.dpi, config.g200params.color); + cap->open(config,fpgaparam); + int ch = 0; + int ixx = 0; + unsigned int fpgaversion; + regs->read(15, fpgaversion); + std::cout << "fpgaversion:" << fpgaversion << std::endl; -#ifdef LOOP_DEBUG - height = delay_done(regs, delaytimes[ix % (sizeof(delaytimes) / sizeof(delaytimes[0]))]); - std::cout << string_format("88888%dth grab time height = %d", ix, height) << std::endl; - height = std::min(fixedheight, height); -#endif - if (data = cap->readFrame(3000)) + // for (int i = 0; i < 0x10; i++) + // { + // sw.reset(); + // if (regs->read(i, val)) + // std::cout << string_format("reg[%d] = 0x%08x\n", i, val); + // else + // std::cout << "read regs error " << std::endl; + // } + int ix = 0; + int width = cap->width(); + int fixedheight = cap->height(); + int type = cap->color(); + int height = fixedheight; + if (type == CV_8UC3) { - //std::cout << string_format("%dth grab time height = %d: %fms", ix, height, sw.elapsed_ms()) << std::endl; - //std::cout << string_format("grab time width = %d, height = %d, type = %d: %fms", width, height, type, sw.elapsed_ms()) << std::endl; - -#ifndef LOOP_DEBUG - cv::Mat mat=GetMergeMat(data,cap->width(),cap->height(),cap->color()); - //mat = cv::Mat(height, width, type, data); - cv::imwrite( std::to_string(ix++)+ ".jpg", mat); - //std::cout << string_format("%dth grab time height = %d: %fms", ix, height, sw.elapsed_ms()) << std::endl; - // sw.reset(); - // savebitmap(data, width, height, true, std::to_string(ix) + ".jpg"); - // std::cout << string_format("%dth grab save time : %fms", ix, sw.elapsed_ms()) << std::endl; - // sw.reset(); - // memset(data, 0, width * height * 3); - // std::cout << string_format("%dth memset time : %fms", ix, sw.elapsed_ms()) << std::endl; -#endif + height = fixedheight / 3; + width = width * 2 * 3 * 3; + type = CV_8UC1; } else { - std::cout << "error :" << ix << std::endl; -#ifdef LOOP_DEBUG - break; -#endif + height = fixedheight; + width = width * 2 * 3; } + + for (int i = 0; i < 100; i++) + { + + ix++; + sw.reset(); + cap->snap(); + +#ifdef LOOP_DEBUG + height = delay_done(regs, delaytimes[ix % (sizeof(delaytimes) / sizeof(delaytimes[0]))]); + std::cout << string_format("%dth grab time height = %d", ix, height) << std::endl; + height = std::min(fixedheight, height); +#endif + if (data = cap->readFrame(5000)) + { + std::cout << string_format("grab time width = %d, height = %d, type = %d: %fms", width, height, type, sw.elapsed_ms()) << std::endl; + sw.reset(); + int channel = cap->color() == 16 ? 3 : 1; + int dstwith = cap->width() * 2 * 3; + int dstHeight = height; + cv::Mat mat(dstHeight, dstwith * channel, CV_8UC1, data); + int dstwidth = type==CV_8UC1?width:width/3; + cv::Mat saveMat =GetMergeMat(dstwidth, height, type,mat,0x00090001); + + std::string savepath = std::to_string(++looptimes) + ".bmp"; + cv::imwrite(savepath, saveMat); + //auto smat = MergeImage(channel == 3 ? 1 : 0, mat, dstwith, dstHeight); + //auto ok = cv::imwrite(savepath, smat); + // if (!ok) + // std::cout << "error save file :" << savepath << std::endl; + } + else + { + std::cout << "error :" << ix << std::endl; +#ifdef LOOP_DEBUG + break; +#endif + } + } + cap->close(); } - std::cout << "type enter to continue" << std::endl; } return 0; diff --git a/device/gxx-linux/testdisplay/main.cpp b/device/gxx-linux/testdisplay/main.cpp new file mode 100644 index 0000000..12da96f --- /dev/null +++ b/device/gxx-linux/testdisplay/main.cpp @@ -0,0 +1,18 @@ +#include +#include +#include "MotorController.h" +#include "MenuComponent.h" + +int main() +{ + MotorController mtctrl; + //MenuComponent com; + //com.initmenu(); + //com.select(); + while (1) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + return 0; +} \ No newline at end of file diff --git a/device/gxx-linux/testdisplay/xmake.lua b/device/gxx-linux/testdisplay/xmake.lua new file mode 100644 index 0000000..88e2215 --- /dev/null +++ b/device/gxx-linux/testdisplay/xmake.lua @@ -0,0 +1,8 @@ +add_rules("mode.debug", "mode.release") + +target("testdisplay") + set_kind("binary") + add_files("*.cpp") + add_syslinks("pthread") + add_deps("motorcontroller","keymonitor") + add_packages("common") diff --git a/device/gxx-linux/testimgproc/main.cpp b/device/gxx-linux/testimgproc/main.cpp index e49f495..a9c9d29 100644 --- a/device/gxx-linux/testimgproc/main.cpp +++ b/device/gxx-linux/testimgproc/main.cpp @@ -4,10 +4,139 @@ #include "opencv2/opencv.hpp" #include #include "StopWatch.h" - +#include #include "iimageencode.h" #include "imageencode.h" + +std::vector caculate(const std::vector& points_x, const std::vector& points_y) +{ + int MaxElement = points_x.size() - 1; + //计算常数f + double f = points_y[0]; + //求解 + int n, m; + //double a[MaxElement][MaxElement+1]; + std::vector> a; + //a.resize(MaxElement); + for (int i = 0; i < MaxElement; i++) + { + std::vector b; + b.resize(MaxElement + 1); + a.push_back(b); + } + + for (int i = 0; i < MaxElement; i++) + { + for (int j = 0; j < MaxElement; j++) + a[i][j] = cv::pow(points_x[i + 1], MaxElement - j); + a[i][MaxElement] = points_y[i + 1] - f; + } + + int i, j; + n = MaxElement; + + for (j = 0; j < n; j++) + { + double max = 0; + double imax = 0; + for (i = j; i < n; i++) + if (imax < cv::abs(a[i][j])) + { + imax = cv::abs(a[i][j]); + max = a[i][j];//得到各行中所在列最大元素 + m = i; + } + + if (cv::abs(a[j][j]) != max) + { + double b = 0; + for (int k = j; k < n + 1; k++) + { + b = a[j][k]; + a[j][k] = a[m][k]; + a[m][k] = b; + } + } + + for (int r = j; r < n + 1; r++) + a[j][r] = a[j][r] / max;//让该行的所在列除以所在列的第一个元素,目的是让首元素为1 + + for (i = j + 1; i < n; i++) + { + double c = a[i][j]; + if (c == 0.0) continue; + for (int s = j; s < n + 1; s++) + a[i][s] = a[i][s] - a[j][s] * c;//前后行数相减,使下一行或者上一行的首元素为0 + } + } + + for (i = n - 2; i >= 0; i--) + for (j = i + 1; j < n; j++) + a[i][n] = a[i][n] - a[j][n] * a[i][j]; + + std::vector result; + for (int k = 0; k < n; k++) + result.push_back(a[k][n]); + result.push_back(f); + return result; +} + +void hsvCorrect_init(uint* table) +{ + cv::Mat mat_rgbTable(256 * 256, 256, CV_8UC3); + uchar* ptr_mat_rgbTable = mat_rgbTable.data; + for (size_t r = 0; r < 256; r++) + for (size_t g = 0; g < 256; g++) + for (size_t b = 0; b < 256; b++, ptr_mat_rgbTable += 3) + { + ptr_mat_rgbTable[0] = b; + ptr_mat_rgbTable[1] = g; + ptr_mat_rgbTable[2] = r; + } + + cv::cvtColor(mat_rgbTable, mat_rgbTable, cv::COLOR_BGR2HSV_FULL); + + uchar table_data[256]; + cv::Mat tableLUT(256, 1, CV_8UC1, table_data); + std::vector points_x, points_y, coefficient; + points_x = { 0, 80, 175, 255 }; + points_y = { 12, 85, 175, 270 }; + coefficient = caculate(points_x, points_y); + for (int j = 0; j < 256; j++) + table_data[j] = static_cast(cv::max(0.0, coefficient[0] * j * j * j + coefficient[1] * j * j + coefficient[2] * j + coefficient[3])); + + cv::Mat hsv_ms[3]; + cv::split(mat_rgbTable, hsv_ms); + cv::LUT(hsv_ms[0], tableLUT, hsv_ms[0]); + cv::merge(hsv_ms, 3, mat_rgbTable); + + cv::cvtColor(mat_rgbTable, mat_rgbTable, cv::COLOR_HSV2BGR_FULL); + + cv::Mat mat_bgr32(256, 256 * 256, CV_8UC4); + cv::cvtColor(mat_rgbTable, mat_bgr32, cv::COLOR_BGR2BGRA); + + memcpy(table, mat_bgr32.data, mat_bgr32.total() * sizeof(uint)); +} + +void hsvCorrect(cv::Mat& image, uint* table) +{ + if (image.channels() != 3) + return; + + cv::Mat bgra; + cv::cvtColor(image, bgra, cv::COLOR_BGR2BGRA); + uint* ptr = bgra.ptr(); + int rows = bgra.rows, cols = bgra.cols; + for (int i = 0; i < rows; i++) + { + ptr = reinterpret_cast(bgra.ptr(i)); + for (int j = 0; j < cols; j++) + ptr[j] = table[ptr[j] & 0x00ffffff]; + } + cv::cvtColor(bgra, image, cv::COLOR_BGRA2BGR); +} + static std::string read_all_from(std::string path) { int t; @@ -26,16 +155,20 @@ int main() //std::string straa = read_all_from("/mnt/d/3.tif"); //fipMemoryIO mio((unsigned char*)straa.c_str(), straa.size()); //auto filet = mio.getFileType(); - std::string imgpath = "/root/.scanner/log/raw.bmp"; - cv::Mat mat=cv::imread(imgpath,cv::IMREAD_COLOR); - if(mat.empty()) - { - std::cout<<" empty image "< buffer; - cv::imencode(".jpg", mat,buffer); - std::cout<<" imencode image done"<encode(mat); return 0; } \ No newline at end of file diff --git a/device/gxx-linux/testkeymonitor/main.cpp b/device/gxx-linux/testkeymonitor/main.cpp new file mode 100644 index 0000000..989986c --- /dev/null +++ b/device/gxx-linux/testkeymonitor/main.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include "keymonitor.h" +#include "uartregsaccess.h" +#include "config.h" +#include "DisplayCenter.h" +#include "MenuComponent.h" +int main() +{ + MenuComponent m_menu; + m_menu.initmenu(); + auto displayCenter = std::shared_ptr(new DisplayCenter()); + displayCenter->PutMsg(DisType::Dis_Welcome, 0,ClearScreen::All); + displayCenter->PutMsg(DisType::Dis_Idel, 0,ClearScreen::All); + auto motorregs = std::shared_ptr(new UartRegsAccess(MOTOR_UART, 921600, 0x07, 0x87)); + auto keycall = [&](int keyvalye) + { + // std::cout << "keycallback keyvalue= " << keyvalye << std::endl; + // auto key = (KeyMonitor::HGKey)(keyvalye); + // switch (key) + // { + // case KeyMonitor::HGKey::Key_Enter: + // displayCenter->PutMsg(DisType::Dis_Err_AqrImgTimeout, 0); + // break; + // case KeyMonitor::HGKey::Key_Cancle: + // displayCenter->PutMsg(DisType::Dis_Idel, 0); + // break; + // case KeyMonitor::HGKey::Key_Count: + // displayCenter->PutMsg(DisType::Dis_Count_Page, 0); + // break; + // case KeyMonitor::HGKey::Key_Handle: + // displayCenter->PutMsg(DisType::Dis_Err_HandModeJam, 0); + // break; + // case KeyMonitor::HGKey::Key_DoubleFeed: + // displayCenter->PutMsg(DisType::Dis_Err_DoubleFeed, 0); + // break; + // case KeyMonitor::HGKey::Key_Left: + // displayCenter->PutMsg(DisType::Dis_Set_PollPI_Low, 0); + // break; + // case KeyMonitor::HGKey::Key_Menu: + // displayCenter->PutMsg(DisType::Dis_Set_PollPI_Mid, 0); + // break; + // case KeyMonitor::HGKey::Key_Right: + // displayCenter->PutMsg(DisType::Dis_Set_PollPI_High, 0); + // break; + // case KeyMonitor::HGKey::Key_Clear: + // displayCenter->PutMsg(DisType::Dis_Err_PaperScrew, 0); + // break; + // default: + // break; + // } + printf("keyvalue %d ",keyvalye); + m_menu.option(keyvalye); + displayCenter->PutMsg(m_menu.getcurtype(),0,ClearScreen::All); + motorregs->write(0x6, 128); + motorregs->write(0x6, 0); + }; + KeyMonitor monitor(keycall); + while (1) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + return 0; +} \ No newline at end of file diff --git a/device/gxx-linux/testkeymonitor/xmake.lua b/device/gxx-linux/testkeymonitor/xmake.lua new file mode 100644 index 0000000..aaea5ac --- /dev/null +++ b/device/gxx-linux/testkeymonitor/xmake.lua @@ -0,0 +1,7 @@ +add_rules("mode.debug", "mode.release") + +target("testkeymonitor") + set_kind("binary") + add_files("*.cpp") + add_deps("keymonitor","regs","conf","display","motorcontroller") + add_packages("common") diff --git a/device/gxx-linux/testlcd/main.cpp b/device/gxx-linux/testlcd/main.cpp new file mode 100644 index 0000000..518296e --- /dev/null +++ b/device/gxx-linux/testlcd/main.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include "DisplayCenter.h" +#include "LCDDisplay.h" +#include + +using namespace std; +std::vector vcdistype={ + DisType::Dis_Init,//启动欢迎界面 + DisType::Dis_Welcome, + DisType::Dis_Idel,//就绪 + DisType::Dis_Set_ClearPaperPass, + DisType::Dis_Set_Count, + DisType::Dis_Err_DoubleFeed, + DisType::Dis_Err_Stable, + DisType::Dis_Err_CoverOpen, + DisType::Dis_Err_JamIn, + DisType::Dis_Err_JamOut, + DisType::Dis_Err_HandModeJam, + DisType::Dis_Err_PaperScrew, + DisType::Dis_Err_FeedError, + DisType::Dis_Err_AqrImgTimeout, + DisType::Dis_Set_PollPaperIntensity, + DisType::Dis_Set_PollPI_High, + DisType::Dis_Set_PollPI_Mid, + DisType::Dis_Set_PollPI_Low, + DisType::Dis_Count_Page, + DisType::Dis_Scan_Page, + DisType::Dis_Device_Lock +}; +int main() +{ + cout << "********** testlcd **********" << endl; + uint64_t cout =0; + LCDDisplay lcd; + while (1) + { + //for (size_t i = 0; i < vcdistype.size(); i++) + { + //lcd.PutMsg(vcdistype[i],i,ClearScreen::All); + //std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + lcd.DisplayState(DisType::Dis_Count_Page,cout++,ClearScreen::All); + std::cout <<"**********"<< cout<<"**********"<< endl; + } + + return 0; +} \ No newline at end of file diff --git a/device/gxx-linux/testlcd/xmake.lua b/device/gxx-linux/testlcd/xmake.lua new file mode 100644 index 0000000..d7cc322 --- /dev/null +++ b/device/gxx-linux/testlcd/xmake.lua @@ -0,0 +1,7 @@ +add_rules("mode.debug", "mode.release") + +target("testlcd") + set_kind("binary") + add_files("*.cpp") + add_packages("common") + add_deps("display") \ No newline at end of file diff --git a/device/gxx-linux/testmotorboard/main.cpp b/device/gxx-linux/testmotorboard/main.cpp index f71b48f..b9ce8a0 100644 --- a/device/gxx-linux/testmotorboard/main.cpp +++ b/device/gxx-linux/testmotorboard/main.cpp @@ -10,6 +10,7 @@ #include "uartregsaccess.h" #include "Gpio.h" #include "StopWatch.h" +#include "wakeup.hpp" using namespace std; @@ -39,7 +40,14 @@ int main() { FileTools ft("/home/linaro/regs.log"); ft.clear(); - MotorBoard mb; + WakeUp wake; + MotorBoard mb(nullptr); + wake.setinitcallback([&mb]{ + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + mb.init_statecontrol(); + },[&mb]{ + mb.release_statecontrol(); + }); unsigned int val = 0; //GpioOut gpio(151); bool exit = false; @@ -52,8 +60,9 @@ int main() case 0: exit = true; break; - case 1:{ - mb.start(); + case 1: + { + mb.start({0}); break; } case 2: @@ -62,9 +71,42 @@ int main() case 3: mb.clear_error(); break; - case 4: - mb.pick_paper(); + case 4:{ + { + int size = 20; + std::cin >> size; + for(int x = 0;x< size;x++){ + mb.pick_paper(); + if(x > 20 && ((x%21) == 0) ) + { + wake.power_off(); + this_thread::sleep_for(chrono::seconds(5)); + wake.power_on(); + this_thread::sleep_for(chrono::seconds(5)); + for (int i = 0; i < 8; i++) + { + StopWatch sw; + // gpio.setValue(Gpio::Low); + // gpio.setValue(Gpio::High); + if (mb.read(i, val)) + { + // gpio.setValue(Gpio::Low); + std::cout << string_format("read : %f\n", sw.elapsed_ms()); + std::cout << hex; + std::cout << "reg[0x" << i << "] =0x" << setw(8) << setfill('0') << val << std::endl; + } + else + { + std::cout << "read regs error " << std::endl; + } + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + std::cout << "send == "<< x << std::endl; + } + } break; + } case 5: { for (int i = 0; i < 8; i++) @@ -110,30 +152,49 @@ int main() printf("motorboard callback mb_osmode_call changed"); }; - MotorBoardGlue mb_glue = {mb_error_call, mb_scandone_call, mb_osmode_call,nullptr,nullptr,nullptr}; + auto mb_set_sleeptime_call = [&](unsigned int speedmode) + { + printf("\n mb_set_sleeptime_call val= %d ", speedmode); + }; + MotorBoardGlue mb_glue = {mb_error_call, mb_scandone_call, mb_osmode_call, mb_set_sleeptime_call,nullptr,nullptr,nullptr}; mb.set_callbacks(mb_glue); done_scan = 0; - mb.start(); - mb.set_speed_mode(1, 200, 1); + mb.SetKeyState(true); + unsigned int reg0; + mb.read(0x00, reg0); + SMBCONFIG *smb_config = (SMBCONFIG *)®0; + smb_config->dpi_mode = 0; + mb.write(0x00, reg0); + mb.set_speed_mode(2); + mb.clear_error(); + //mb.set_cuospeed(41); + mb.start({0}); + mb.pick_paper(); + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); StopWatch sw; + int num = 0; for (;;) { - if (mb.wait_paper_out(3000)) + if (mb.wait_paper_in(1000)) { // std::this_thread::sleep_for(std::chrono::milliseconds(100)); - std::cout << __func__ << " call: paper pick" << std::endl; - mb.pick_paper(); - sw.reset(); + std::cout << __func__ << " call: paper pick num = "<< num++ << std::endl; + //std::this_thread::sleep_for(std::chrono::milliseconds(1000));//simulate capture + if(mb.wait_paper_out(1000)) + { + std::cout << __func__ << " call: paper out stop snap " < 3) - done_scan = -2; - } + //else + // { + // if (sw.elapsed_s() > 3) + // done_scan = -2; + // } + mb.pick_paper(); } std::cout << __func__ << " call: exit" << std::endl; } diff --git a/device/gxx-linux/testscanner/main.cpp b/device/gxx-linux/testscanner/main.cpp index a34ccbe..200e369 100644 --- a/device/gxx-linux/testscanner/main.cpp +++ b/device/gxx-linux/testscanner/main.cpp @@ -4,8 +4,11 @@ #include "scannerregs.h" #include "usbservice.h" #include "motorboard.h" +#include "ICapturer.h" #include "Capturer.h" +#include "MonoCapturer.h" #include "imageusbhandler.h" +#include "CImageMerge.h" using namespace std; int menu() { @@ -16,6 +19,7 @@ int menu() { cout << "(2) stop. " << endl; cout << "(3) count. " << endl; cout << "(4) mode. " << endl; + cout << "(5) testcorrect"<> choice; @@ -25,10 +29,15 @@ int menu() { int main() { + // auto img = cv::imread("/home/linaro/anlogic_gxx_linux/0_org.jpg",cv::IMREAD_GRAYSCALE); + // auto retmat = CImageMerge().MergeImage(true,img,7776,150,0x90001); + // img.release(); + // cv::imwrite("/home/linaro/anlogic_gxx_linux/0_org_t.jpg",retmat); + // return 1; bool exit = false; - std::shared_ptr motorboard(new MotorBoard()); - std::shared_ptr capturer(new Capturer()); - std::shared_ptr scanner(new Scanner(capturer, motorboard,nullptr)); + std::shared_ptr motorboard(new MotorBoard(nullptr)); + std::shared_ptr capturer(new MonoCapturer()); + std::shared_ptr scanner(new Scanner(capturer, motorboard,nullptr)); std::shared_ptr scannerRegs(new ScannerRegAccess(scanner)); scanner->set_imagehandler(std::shared_ptr(new ImageUsbHandler())); int option; @@ -41,7 +50,25 @@ int main() exit = true; break; case 1: + HGScanConfig cfg;//={ + cfg.g200params.paper = 16; + cfg.g200params.color=0; + cfg.g200params.dpi = 0x02; + cfg.g200params.double_feed_enbale=0; + cfg.g200params.stable_enbale = 0; + cfg.g200params.screw_detect_enable = 0; + cfg.g200params.screw_detect_level = 0; + cfg.g200params.iscorrect_mode = 0; + cfg.g200params.en_autosize = 0; + cfg.g200params.pc_correct=0; + cfg.g200params.enable_sizecheck = 0; + cfg.g200params.enabledsp_cache = 0; + cfg.g200params.sizeerror_errorratio = 0; + //}; + scanner->configparam(cfg); scanner->start_scan(); + while(1) + std::this_thread::sleep_for(chrono::milliseconds(1)); break; case 2: scanner->stop_scan(); @@ -51,6 +78,8 @@ int main() break; case 4: std::cout << "os mode" << scanner->mode() << std::endl; + case 5 : + scanner->test_autocorrect(0); default: cout << "nop, Please select again! " << endl; break; diff --git a/device/gxx-linux/testthread b/device/gxx-linux/testthread new file mode 100644 index 0000000000000000000000000000000000000000..dc719b7001e6b0843007a4904126a37276d2dd43 GIT binary patch literal 28672 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 choice; - if(choice == 6) - system("clear"); - return choice; } int main() { + auto cap = std::shared_ptr(new Capturer()); + auto mt = std::shared_ptr(new MotorBoard(nullptr)); + auto scanner = std::shared_ptr(new Scanner(cap, mt,nullptr)); + UsbService us(cap->regs(), mt->regs()); + auto notify = us.notify(); + std::shared_ptr usbImage(new UsbImageProcQueue(notify)); + auto transfer = us.transmiter(); + std::shared_ptr regs = std::shared_ptr(new ScannerRegAccess(scanner, usbImage, transfer)); + scanner->set_imagehandler(std::shared_ptr(new ImageUsbHandler(usbImage))); + us.set_scannerregs(regs); + unsigned int val = 0; + bool exit = false; + int option = 0; + unsigned char data[116] = {0x00}; + int count = 0; + + // auto mem = std::shared_ptr(new VectorMemroy()); + // mem->resize(10); + // memcpy(mem->data(),data,sizeof(data)); + for (;;) { - auto cap = std::shared_ptr(new Capturer()); - auto mt = std::shared_ptr(new MotorBoard()); - auto scanner = std::shared_ptr(new Scanner(cap, mt,nullptr)); - UsbService us(cap->regs(), mt->regs()); - auto notify = us.notify(); - std::shared_ptr usbImage(new UsbImageProcQueue(notify)); - auto transfer = us.transmiter(); - std::shared_ptr regs = std::shared_ptr(new ScannerRegAccess(scanner, usbImage, transfer)); - scanner->set_imagehandler(std::shared_ptr(new ImageUsbHandler(usbImage))); - us.set_scannerregs(regs); - unsigned int val = 0; - bool exit = false; - int option = 0; - unsigned char data[116] = {0x00}; - int count = 0; - - - //* - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - for(;;) + option = menu(); + switch (option) { - if(menu() == 0) - break; + case 0: + exit = true; + break; + case 1: + this_thread::sleep_for(chrono::milliseconds(1)); + break; + case 2: + notify->clear(); + break; + case 3: + // { + // auto nread= transfer->read_bulk(data,sizeof(data)); + // break; + // } + case 4: + scanner->test_autocorrect(option==3); + break; + case 5: + { + + HGScanConfig config = {0}; + for (size_t i = 0; i < 40; i++) + { + std::string msg=(i % 2 == 0?" mode COLOR ":" mode GRAY "); + std::cout << "Test color mode change index = "<test_cap(config); + this_thread::sleep_for(chrono::milliseconds(1)); + } + std::cout << "Please select again! " << std::endl; + break; } - transfer.reset(); - /*/ - while(1) std::this_thread::sleep_for(std::chrono::milliseconds(1)); - ///////*//// - - return 0; + default: + std::cout << "Please select again! " << std::endl; + break; + } + /* code */ + if (exit) + break; } - // auto cap = std::shared_ptr(new Capturer()); - // auto mt = std::shared_ptr(new MotorBoard()); - // auto scanner = std::shared_ptr(new Scanner(cap, mt,nullptr)); - // UsbService us(cap->regs(), mt->regs()); - // auto notify = us.notify(); - // std::shared_ptr usbImage(new UsbImageProcQueue(notify)); - // auto transfer = us.transmiter(); - // std::shared_ptr regs = std::shared_ptr(new ScannerRegAccess(scanner, usbImage, transfer)); - // scanner->set_imagehandler(std::shared_ptr(new ImageUsbHandler(usbImage))); - // us.set_scannerregs(regs); - // unsigned int val = 0; - // bool exit = false; - // int option = 0; - // unsigned char data[116] = {0x00}; - // int count = 0; - - // // auto mem = std::shared_ptr(new VectorMemroy()); - // // mem->resize(10); - // // memcpy(mem->data(),data,sizeof(data)); - // for (;;) - // { - // option = menu(); - // switch (option) - // { - // case 0: - // exit = true; - // break; - // case 1: - // this_thread::sleep_for(chrono::milliseconds(1)); - // break; - // case 2: - // notify->clear(); - // break; - // case 3: - // // { - // // auto nread= transfer->read_bulk(data,sizeof(data)); - // // break; - // // } - // case 4: - // scanner->test_autocorrect(option==3); - // break; - // case 5: - // { - - // HGScanConfig config = {0}; - // for (size_t i = 0; i < 40; i++) - // { - // std::string msg=(i % 2 == 0?" mode COLOR ":" mode GRAY "); - // std::cout << "Test color mode change index = "<test_cap(config); - // this_thread::sleep_for(chrono::milliseconds(1)); - // } - // std::cout << "Please select again! " << std::endl; - // break; - // } - // default: - // std::cout << "Please select again! " << std::endl; - // break; - // } - // /* code */ - // if (exit) - // break; - // } std::cout << "exit munu" << std::endl; diff --git a/device/gxx-linux/testusb/usb-rk3399/inc/buildconf.h b/device/gxx-linux/testusb/usb-rk3399/inc/buildconf.h deleted file mode 100644 index 88ff97f..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/inc/buildconf.h +++ /dev/null @@ -1,12 +0,0 @@ -#define _LARGEFILE64_SOURCE -#define _FILE_OFFSET_BITS 64 - -//#define CONFIG_USB_NON_BLOCKING_WRITE 1 - -#define CONFIG_USB_FS_SUPPORT 1 // USB 1.1 Full speed -#define CONFIG_USB_HS_SUPPORT 1 // USB 2.0 High speed -#define CONFIG_USB_SS_SUPPORT 1 // USB 3.0 SuperSpeed - -#define CONFIG_READ_FILE_BUFFER_SIZE (1024*1024) // Must be a 2^x value. -#define CONFIG_MAX_TX_USB_BUFFER_SIZE (16*512) // Must be a multiple of 512 and be less than CONFIG_READ_FILE_BUFFER_SIZE -#define CONFIG_MAX_RX_USB_BUFFER_SIZE (16*512) // Must be a multiple of 512 \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/inc/camtp.h b/device/gxx-linux/testusb/usb-rk3399/inc/camtp.h deleted file mode 100644 index 9602676..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/inc/camtp.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * CAMTP Responder - * Copyright (c) 2020 Holdtecs Technologies - * - * CAMTP Responder 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.0 of the License, or (at your option) any later version. - * - * CAMTP Responder 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 version 3 for more details. - * - * You should have received a copy of the GNU General Public License - * along with CAMTP Responder; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file camtp.h - * @brief Main CAMMTP protocol functions. - * @author Barry Ruan - */ - -#ifndef _INC_CAMTP_H_ -#define _INC_CAMTP_H_ - -#define MAX_STORAGE_NB 16 -#define MAX_CFG_STRING_SIZE 512 - -#pragma pack() -typedef struct mtp_usb_cfg_ -{ - uint16_t usb_vendor_id; - uint16_t usb_product_id; - uint8_t usb_class; - uint8_t usb_subclass; - uint8_t usb_protocol; - uint16_t usb_dev_version; - uint16_t usb_max_packet_size; - uint8_t usb_functionfs_mode; - - char usb_device_path[MAX_CFG_STRING_SIZE + 1]; - char usb_endpoint_in[MAX_CFG_STRING_SIZE + 1]; - char usb_endpoint_out[MAX_CFG_STRING_SIZE + 1]; - char usb_endpoint_intin[MAX_CFG_STRING_SIZE + 1]; - - char usb_string_manufacturer[MAX_CFG_STRING_SIZE + 1]; - char usb_string_product[MAX_CFG_STRING_SIZE + 1]; - char usb_string_serial[MAX_CFG_STRING_SIZE + 1]; - char usb_string_version[MAX_CFG_STRING_SIZE + 1]; - - char usb_string_interface[MAX_CFG_STRING_SIZE + 1]; - - int wait_connection; - int loop_on_disconnect; - - int show_hidden_files; - - int val_umask; - -}camtp_usb_cfg; - - -typedef struct camtp_ctx_ -{ - uint32_t session_id; - - camtp_usb_cfg usb_cfg; - - void * usb_ctx; - - volatile int cancel_req; - -}camtp_ctx; - -int camtp_load_config_file(camtp_ctx * context, const char * conffile); - -#endif \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/inc/default_cfg.h b/device/gxx-linux/testusb/usb-rk3399/inc/default_cfg.h deleted file mode 100644 index 8030c5d..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/inc/default_cfg.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * CAMTP Responder - * Copyright (c) 2020 Holdtecs Technologies - * - * CAMTP Responder 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.0 of the License, or (at your option) any later version. - * - * CAMTP Responder 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 version 3 for more details. - * - * You should have received a copy of the GNU General Public License - * along with CAMTP Responder; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file default.h - * @brief Main CAMMTP protocol functions. - * @author Barry Ruan - */ - -#ifndef _INC_DEFAULT_CFG_H_ -#define _INC_DEFAULT_CFG_H_ - -#ifndef CAMTPR_CONF_FILE -#define CAMTPR_CONF_FILE "/etc/camtprd/camtprd.conf" -#endif - -#define MAX_PACKET_SIZE 1024 - -#define USB_DEV_VENDOR_ID 0x04b4 -//0x04B4 // Linux Foundation -#define USB_DEV_PRODUCT_ID 0x8613 // PTP Gadget - -#define USB_DEV_CLASS 0x6 // Still Imaging device -#define USB_DEV_SUBCLASS 0x0 // -#define USB_DEV_PROTOCOL 0x0 // - -#define USB_DEV_VERSION 0x3008 - -#define USB_FFS_MODE 1 - -#define USB_DEV "/dev/ffs-camtp/ep0" - -#define USB_EPIN "/dev/ffs-camtp/ep1" -#define USB_EPOUT "/dev/ffs-camtp/ep2" -#define USB_EPINTIN "/dev/ffs-camtp/ep3" - -#define MANUFACTURER "HUAGAO Technologies" -#define PRODUCT "HUAGAO" -#define SERIALNUMBER "01234567ABCDEFG" - -#endif diff --git a/device/gxx-linux/testusb/usb-rk3399/inc/logs_out.h b/device/gxx-linux/testusb/usb-rk3399/inc/logs_out.h deleted file mode 100644 index 57a33ff..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/inc/logs_out.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * CAMTP Responder - * Copyright (c) 2020 Holdtecs Technologies - * - * CAMTP Responder 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.0 of the License, or (at your option) any later version. - * - * CAMTP Responder 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 version 3 for more details. - * - * You should have received a copy of the GNU General Public License - * along with CAMTP Responder; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file logs_out.h - * @brief Log output functions - * @author *** - */ - -#ifndef _INC_DEBUG_OUT_H_ -#define _INC_DEBUG_OUT_H_ -#include "stringex.hpp" -#include "applog.h" - -#define RUN_TEST - -const std::string loggername = "camtprd"; - -void timestamp(char * timestr, int maxsize); - -#define SIZEHEX PRIx64 -#define DEBUG -#ifdef USE_SYSLOG - -#include - -#else - -#ifdef DEBUG -#include -#endif - -#endif - -#if defined(WIN32) || defined(RUN_TEST) - -#define PRINT_DEBUG printf -#define PRINT_ERROR printf -#define PRINT_MSG - -#elif defined(USE_SYSLOG) // Syslog usage - -#define PRINT_MSG(fmt, args...) syslog(LOG_NOTICE, "[CAMTPrd - Info] " fmt "\n", \ - ## args) -#define PRINT_ERROR(fmt, args...) syslog(LOG_ERR, "[CAMTPrd - Error] " fmt "\n", \ - ## args) -#define PRINT_WARN(fmt, args...) syslog(LOG_WARNING, "[CAMTPrd - Warning] " fmt "\n", \ - ## args) -#ifdef DEBUG - -#define PRINT_DEBUG(fmt, args...) syslog(LOG_DEBUG, "[CAMTPrd - Debug] " fmt "\n", \ - ## args) -#else - -#define PRINT_DEBUG(fmt, args...) - -#endif - -#else // Stdout usage - -// #define PRINT_MSG(fmt, args...) { \ -// char timestr[32]; \ -// timestamp((char*)×tr, sizeof(timestr)); \ -// fprintf(stdout, \ -// "[CAMTPrd - %s - Info] " fmt "\n",(char*)×tr, \ -// ## args); \ -// fflush(stdout); \ -// } - -#define PRINT_MSG(fmt, args...) { \ - char timestr[32]; \ - timestamp((char*)×tr, sizeof(timestr)); \ - LOG_INFO(string_format("[CAMTPrd - %s - Info] " fmt "\n",(char*)×tr, ## args)); \ - } - - -#define PRINT_ERROR(fmt, args...) { \ - char timestr[32]; \ - timestamp((char*)×tr, sizeof(timestr)); \ - LOG_ERROR(string_format("[CAMTPrd - %s - Info] " fmt "\n",(char*)×tr, ## args)); \ - } - -#define PRINT_WARN(fmt, args...) { \ - char timestr[32]; \ - timestamp((char*)×tr, sizeof(timestr)); \ - LOG_WARN(string_format("[CAMTPrd - %s - Info] " fmt "\n",(char*)×tr, ## args)); \ - } - -#ifdef DEBUG -#define PRINT_DEBUG(fmt, args...) { \ - char timestr[32]; \ - timestamp((char*)×tr, sizeof(timestr)); \ - LOG_DEBUG(string_format("[CAMTPrd - %s - Info] " fmt "\n",(char*)×tr, ## args)); \ - } -#else - -#define PRINT_DEBUG(fmt, args...) - -#endif - -#endif - -#ifdef DEBUG - -#define PRINT_DEBUG_BUF(x, y) printbuf( x, y ); -void printbuf(void * buf,int size); - -#else - -#define PRINT_DEBUG_BUF(x, y) - -#endif - -#endif - diff --git a/device/gxx-linux/testusb/usb-rk3399/inc/usb_gadget.h b/device/gxx-linux/testusb/usb-rk3399/inc/usb_gadget.h deleted file mode 100644 index 171b86f..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/inc/usb_gadget.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * CAMTP Responder - * Copyright (c) 2020 Holdtecs Technologies - * - * CAMTP Responder 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.0 of the License, or (at your option) any later version. - * - * CAMTP Responder 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 version 3 for more details. - * - * You should have received a copy of the GNU General Public License - * along with CAMTP Responder; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file usb_gadget.c - * @brief USB gadget layer - * @author *** - */ - -#ifndef _INC_USB_GADGET_H_ -#define _INC_USB_GADGET_H_ - -#include -#include -#include - -#include "usbstring.h" - -enum -{ - EP_DESCRIPTOR_IN = 0, - EP_DESCRIPTOR_OUT, - EP_DESCRIPTOR_INT_IN, - - EP_NB_OF_DESCRIPTORS -}; - -#define EP_INT_MODE 0x00000000 -#define EP_BULK_MODE 0x00000001 -#define EP_IN_DIR 0x00000000 -#define EP_OUT_DIR 0x00000002 -#define EP_HS_MODE 0x00000004 -#define EP_SS_MODE 0x00000008 - -typedef struct _EndPointsDesc { - struct usb_interface_descriptor if_desc; - struct usb_endpoint_descriptor_no_audio ep_desc_in; - struct usb_endpoint_descriptor_no_audio ep_desc_out; - struct usb_endpoint_descriptor_no_audio ep_desc_int_in; -} __attribute__((packed)) EndPointsDesc; - -typedef struct _SSEndPointsDesc { - struct usb_interface_descriptor if_desc; - struct usb_endpoint_descriptor_no_audio ep_desc_in; - struct usb_ss_ep_comp_descriptor ep_desc_in_comp; - struct usb_endpoint_descriptor_no_audio ep_desc_out; - struct usb_ss_ep_comp_descriptor ep_desc_out_comp; - struct usb_endpoint_descriptor_no_audio ep_desc_int_in; - struct usb_ss_ep_comp_descriptor ep_desc_int_in_comp; - -} __attribute__((packed)) SSEndPointsDesc; - -typedef struct ep_cfg_descriptor { - struct usb_endpoint_descriptor_no_audio ep_desc; -#ifdef CONFIG_USB_SS_SUPPORT - struct usb_ss_ep_comp_descriptor ep_desc_comp; -#endif -} __attribute__((packed)) ep_cfg_descriptor; - -// Direct GadgetFS mode -typedef struct _usb_cfg -{ - uint32_t head; - -#if CONFIG_USB_FS_SUPPORT - struct usb_config_descriptor cfg_fs; - EndPointsDesc ep_desc_fs; -#endif - -#if CONFIG_USB_HS_SUPPORT - struct usb_config_descriptor cfg_hs; - EndPointsDesc ep_desc_hs; -#endif - -#if CONFIG_USB_SS_SUPPORT - struct usb_config_descriptor cfg_ss; - SSEndPointsDesc ep_desc_ss; -#endif - - struct usb_device_descriptor dev_desc; - -} __attribute__ ((packed)) usb_cfg; - -// FunctionFS mode -typedef struct _usb_ffs_cfg -{ - uint32_t magic; - uint32_t length; -#ifndef OLD_FUNCTIONFS_DESCRIPTORS // Kernel > v3.14 - uint32_t flags; -#endif - -#ifdef CONFIG_USB_FS_SUPPORT - uint32_t fs_count; -#endif - -#ifdef CONFIG_USB_HS_SUPPORT - uint32_t hs_count; -#endif - -#if defined(CONFIG_USB_SS_SUPPORT) && !defined(OLD_FUNCTIONFS_DESCRIPTORS) - uint32_t ss_count; -#endif - -#ifdef CONFIG_USB_FS_SUPPORT - EndPointsDesc ep_desc_fs; -#endif - -#ifdef CONFIG_USB_HS_SUPPORT - EndPointsDesc ep_desc_hs; -#endif - -#if defined(CONFIG_USB_SS_SUPPORT) && !defined(OLD_FUNCTIONFS_DESCRIPTORS) - SSEndPointsDesc ep_desc_ss; -#endif - -} __attribute__ ((packed)) usb_ffs_cfg; - -typedef struct _ffs_strings -{ - struct usb_functionfs_strings_head header; - uint16_t code; - char string_data[128]; // string data. -} __attribute__((packed)) ffs_strings; - -typedef struct _ep_cfg -{ - uint32_t head; - - ep_cfg_descriptor ep_desc[2]; - -} __attribute__ ((packed)) ep_cfg; - -enum { - STRINGID_MANUFACTURER = 1, - STRINGID_PRODUCT, - STRINGID_SERIAL, - STRINGID_CONFIG_HS, - STRINGID_CONFIG_LS, - STRINGID_INTERFACE, - STRINGID_MAX -}; - -#define MAX_USB_STRING 16 - -typedef struct _usb_gadget -{ - int usb_device; - - usb_cfg * usb_config; - usb_ffs_cfg * usb_ffs_config; - - ep_cfg * ep_config[3]; - - int ep_handles[EP_NB_OF_DESCRIPTORS]; - - char * ep_path[3]; - - int stop; - - struct usb_string stringtab[MAX_USB_STRING]; - - int wait_connection; - pthread_t thread; - int thread_not_started; - -}usb_gadget; - -#endif diff --git a/device/gxx-linux/testusb/usb-rk3399/inc/usbdevice.h b/device/gxx-linux/testusb/usb-rk3399/inc/usbdevice.h deleted file mode 100644 index 19ce3a0..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/inc/usbdevice.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include "camtp.h" -#include "buildconf.h" -#include "usb_gadget.h" - -#include "usb_io.h" - -#define ASYNC_EP - -class UsbDevice -{ - async_usb_gadget *usb_; - -#ifdef ASYNC_EP - dyn_mem_ptr unhandled_ep0(struct usb_functionfs_event* pev); - dyn_mem_ptr handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - - std::map> dispatcher_; - dyn_mem_ptr handle_packet_heart_beat(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - dyn_mem_ptr handle_packet_invalid(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - dyn_mem_ptr handle_packet_get_setting(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - dyn_mem_ptr handle_packet_set_setting(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - - void do_system_command(const char* cmd); -#endif - -public: - UsbDevice(std::function handler = std::function(), - std::function call_back = std::function()); - virtual ~UsbDevice(); - - int read_bulk(void* data, int size, int* err = nullptr, bool full = true); - int write_bulk(void* data, int size, int* err = nullptr); - int write_int(void* data, int size, int* err = nullptr); - - void abort_int(); - - bool is_connected() - { - return b_connected; - } - -private: - void usb_main(); - - usb_gadget * init_usb_camtp_gadget(camtp_ctx * ctx); - void deinit_usb_camtp_gadget(usb_gadget * usbctx); - - int handle_ffs_ep0(usb_gadget * ctx); - int handle_ep0(usb_gadget * ctx); - int add_usb_string(usb_gadget * usbctx, int id, char * string); - void fill_ep_descriptor(camtp_ctx * ctx, usb_gadget * usbctx,struct usb_endpoint_descriptor_no_audio * desc,int index,unsigned int flags); - void fill_if_descriptor(camtp_ctx * ctx, usb_gadget * usbctx, struct usb_interface_descriptor * desc); - void fill_config_descriptor(camtp_ctx * ctx , usb_gadget * usbctx,struct usb_config_descriptor * desc,int total_size, int hs); - void fill_dev_descriptor(camtp_ctx * ctx, usb_gadget * usbctx,struct usb_device_descriptor * desc); - - void handle_setup_request(usb_gadget * ctx, struct usb_ctrlrequest* setup); - int init_eps(usb_gadget * ctx, int ffs_mode, bool open_ep = true); - int init_ep(usb_gadget * ctx,int index,int ffs_mode, bool open_ep = true); - int write(int fd, void* data, size_t size, int* err = nullptr); - int read(int fd, void* data, size_t size, int* err = nullptr, bool full = true); - - int dispatch_ep0(struct usb_functionfs_event *ev, size_t len); - - static const int cacheSize; - std::shared_ptr camtp_context; - usb_gadget gadget; - std::function ctrl_handler; - std::function connect_call; - std::thread thread_main; - usb_gadget *usb_ctx; - volatile bool b_connected; - - friend class ep_waiter; -}; \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/inc/usbstring.h b/device/gxx-linux/testusb/usb-rk3399/inc/usbstring.h deleted file mode 100644 index da2dff5..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/inc/usbstring.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * CAMTP Responder - * Copyright (c) 2020 Holdtecs Technologies - * - * CAMTP Responder 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.0 of the License, or (at your option) any later version. - * - * CAMTP Responder 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 version 3 for more details. - * - * You should have received a copy of the GNU General Public License - * along with CAMTP Responder; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - - /** - * @file usbstring.h - * @brief USB strings - Function & structures declarations. - * @author *** - */ - -#ifndef _INC_USBSTRING_H_ -#define _INC_USBSTRING_H_ - -struct usb_string { - uint8_t id; - char *str; -}; - -struct usb_gadget_strings { - uint16_t language; /* 0x0409 for en-us */ - struct usb_string *strings; -}; - -int usb_gadget_get_string (struct usb_gadget_strings *table, int id, uint8_t *buf); -int unicode2charstring(char * str, uint16_t * unicodestr, int maxstrsize); -int char2unicodestring(char * unicodestr, int index, int maxsize, char * str, int unicodestrsize); -#endif diff --git a/device/gxx-linux/testusb/usb-rk3399/inotify.h b/device/gxx-linux/testusb/usb-rk3399/inotify.h deleted file mode 100644 index c97b9a9..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/inotify.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include - -class INotify -{ - public: - virtual ~INotify(){} - - virtual void notify(void* data, int size) = 0; - virtual void clear() = 0; -}; - -typedef std::shared_ptr NotifyPtr; \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/ireceive.h b/device/gxx-linux/testusb/usb-rk3399/ireceive.h deleted file mode 100644 index d662947..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/ireceive.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "imgproc.h" -#include "imemory.h" - -class UsbDevice; -class ThreadEx; - -class IReceive -{ -public: - virtual ~IReceive(){} - - virtual int read(MemoryPtr& memroy) = 0; - virtual int read_bulk(void* data,unsigned int length) = 0; - virtual bool is_reading() = 0; - virtual void cannel() = 0; -}; \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/itransmit.h b/device/gxx-linux/testusb/usb-rk3399/itransmit.h deleted file mode 100644 index c3f19c2..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/itransmit.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "imemory.h" - -class ITransmit -{ -public: - virtual ~ITransmit(){} - virtual int write_bulk(void* data,int size) = 0; - virtual void write(MemoryPtr memroy) = 0; - virtual bool is_writing() = 0; - virtual void cannel() = 0; -}; \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/CMakeLists.txt b/device/gxx-linux/testusb/usb-rk3399/src/common/CMakeLists.txt deleted file mode 100644 index 466b700..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -project(common) -add_compile_options(-std=c++11) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") -aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS) -file(GLOB DIR_HEADS "${PROJECT_SOURCE_DIR}/*" "${PROJECT_SOURCE_DIR}/json/*") -set(DIR_SRCS ${DIR_SRCS} ${DIR_HEADS}) -add_library(${PROJECT_NAME} STATIC ${DIR_SRCS}) - -target_link_libraries(${PROJECT_NAME} PRIVATE - dl - pthread - rt - ) -target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR} - ) -set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../scanner/build/) diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/cmd.cpp b/device/gxx-linux/testusb/usb-rk3399/src/common/cmd.cpp deleted file mode 100644 index d8abf93..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/cmd.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "cmd.h" - - - - -namespace parser -{ - static void command_line_to_arguments(const char* cmdl, std::vector& args) - { - while(*cmdl) - { - const char* h = cmdl; - while(*h == ' ' || *h == '\t') - h++; - if(*h == 0) - break; - - cmdl = h; - if(*h == '\"') - { - cmdl++; - h++; - while(*h) - { - if(*h == '\"') - break; - if(*h == '\\') - h++; - h++; - } - } - else - { - while(*h) - { - if(*h == ' ' || *h == '\t') - break; - h++; - } - } - if(h > cmdl) - args.push_back(std::string(cmdl, h - cmdl)); - else if(*h == '\"') - args.push_back(""); - - if(*h == 0) - break; - - cmdl = h + 1; - } - } -} - - - - -cmd_line::cmd_line() -{} -cmd_line::~cmd_line() -{} - -cmd_line* cmd_line::from_console(const char* tips) -{ - std::string in(""); - char ch = 0; - - if(!tips || *tips == 0) - tips = "input"; - - printf("%s%s>%s", CONSOLE_COLOR_FRONT_BLUE, tips, CONSOLE_COLOR_NONE); - while((ch = getchar()) != '\n') - in.append(1, ch); - - return cmd_line::from_command_line(in.c_str()); -} -cmd_line* cmd_line::from_command_line(const char* cmdl) -{ - cmd_line* cmd = new cmd_line(); - - cmd->cmd_line_ = cmdl; - parser::command_line_to_arguments(cmdl, cmd->arguments_); - - return cmd; -} - -size_t cmd_line::count(void) -{ - return arguments_.size(); -} -const char* cmd_line::parameter(int ind) -{ - if(ind >= 0 && ind < arguments_.size()) - return arguments_[ind].c_str(); - else - return nullptr; -} -const char* cmd_line::parameter(const char* key) -{ - for(int i = 0; i < arguments_.size() - 1; ++i) - { - if(arguments_[i] == key) - return arguments_[i + 1].c_str(); - } - - return nullptr; -} diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/cmd.h b/device/gxx-linux/testusb/usb-rk3399/src/common/cmd.h deleted file mode 100644 index 91a65c3..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/cmd.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -// command line utility -// -// created on 2023-02-10 -// - -#include "referer.h" -#include -#include - -#define CONSOLE_COLOR_NONE "\033[0m" -#define CONSOLE_COLOR_FRONT_BLACK "\033[0;30m" -#define CONSOLE_COLOR_FRONT_DARK_GRAY "\033[1;30m" -#define CONSOLE_COLOR_FRONT_RED "\033[0;31m" -#define CONSOLE_COLOR_FRONT_LIGHT_RED "\033[1;31m" -#define CONSOLE_COLOR_FRONT_GREEN "\033[0;32m" -#define CONSOLE_COLOR_FRONT_LIGHT_GREEN "\033[1;32m" -#define CONSOLE_COLOR_FRONT_BROWN "\033[0;33m" -#define CONSOLE_COLOR_FRONT_YELLOW "\033[1;33m" -#define CONSOLE_COLOR_FRONT_BLUE "\033[0;34m" -#define CONSOLE_COLOR_FRONT_LIGHT_BLUE "\033[1;34m" -#define CONSOLE_COLOR_FRONT_PURPLE "\033[0;35m" -#define CONSOLE_COLOR_FRONT_LIGHT_PURPLE "\033[1;35m" -#define CONSOLE_COLOR_FRONT_CYAN "\033[0;36m" -#define CONSOLE_COLOR_FRONT_LIGHT_CYAN "\033[1;36m" -#define CONSOLE_COLOR_FRONT_LIGHT_GRAY "\033[0;37m" -#define CONSOLE_COLOR_FRONT_WHITE "\033[1;37m" - -#define CONSOLE_COLOR_BACK_BLACK "\033[0;40m" -#define CONSOLE_COLOR_BACK_DARK_GRAY "\033[1;40m" -#define CONSOLE_COLOR_BACK_RED "\033[0;41m" -#define CONSOLE_COLOR_BACK_LIGHT_RED "\033[1;41m" -#define CONSOLE_COLOR_BACK_GREEN "\033[0;42m" -#define CONSOLE_COLOR_BACK_LIGHT_GREEN "\033[1;42m" -#define CONSOLE_COLOR_BACK_BROWN "\033[0;43m" -#define CONSOLE_COLOR_BACK_YELLOW "\033[1;43m" -#define CONSOLE_COLOR_BACK_BLUE "\033[0;44m" -#define CONSOLE_COLOR_BACK_LIGHT_BLUE "\033[1;44m" -#define CONSOLE_COLOR_BACK_PURPLE "\033[0;45m" -#define CONSOLE_COLOR_BACK_LIGHT_PURPLE "\033[1;45m" -#define CONSOLE_COLOR_BACK_CYAN "\033[0;46m" -#define CONSOLE_COLOR_BACK_LIGHT_CYAN "\033[1;46m" -#define CONSOLE_COLOR_BACK_LIGHT_GRAY "\033[0;47m" -#define CONSOLE_COLOR_BACK_WHITE "\033[1;47m" - - -namespace console -{ - // special effects: - // \033[0m close all attributes - // \033[1m set high-light - // \033[4m underline - // \033[5m blink - // \033[7m reverse(反显) - // \033[8m blanking(消隐) - // \033[30m -- \033[37m set foreground color - // \033[40m -- \033[47m set background color - // - // cursor position: - // \033[nA move up n lines - // \033[nB move down n lines - // \033[nC move right n cols - // \033[nD move left n cols - // \033[y;xH set cursor position - // \033[2J clear screen - // \033[K clear the line after cursor position - // \033[s save cursor position - // \033[u restore cursor position - // \033[?25l hide cursor - // \033[?25h show cursor -}; - -class cmd_line : public refer -{ - std::string cmd_line_; - std::vector arguments_; - -protected: - cmd_line(); - ~cmd_line(); - -public: - static cmd_line* from_console(const char* tips); - static cmd_line* from_command_line(const char* cmdl); - -public: - size_t count(void); - const char* parameter(int ind); - const char* parameter(const char* key); -}; - diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/data.cpp b/device/gxx-linux/testusb/usb-rk3399/src/common/data.cpp deleted file mode 100644 index f524ea4..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/data.cpp +++ /dev/null @@ -1,466 +0,0 @@ -#include "data.h" - - -#include - -#if defined(WIN32) || defined(_WIN64) -#include - -namespace sys_util -{ - int get_disk_size(const char* path, uint64_t* total, uint64_t* avail, uint64_t* blocksize) - { - std::string disk(path); - size_t pos = disk.find("\\"); - DWORD spc = 0, bps = 0, avc = 0, tot = 0; - - if (pos++ != std::string::npos) - disk.erase(pos); - if (GetDiskFreeSpaceA(disk.c_str(), &spc, &bps, &avc, &tot)) - { - if (total) - { - *total = tot; - *total *= bps * spc; - } - if (avail) - { - *avail = avc; - *avail *= bps * spc; - } - if (blocksize) - { - *blocksize = bps; - *blocksize *= spc; - } - - return 0; - } - else - { - return GetLastError(); - } - } -} -#else -#include "sys_util.h" -#include -#include -#endif - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -packet_data_base::packet_data_base() : pack_cmd_(0), pack_id_(0) - , progress_notify_(PROGRESS_NOTIFYER()) -{} -packet_data_base::~packet_data_base() -{} - -int packet_data_base::notify_progress(uint64_t total, uint64_t cur_size, uint32_t err) -{ - if (progress_notify_) - progress_notify_(total, cur_size, err); - else - return ENOENT; -} - -void packet_data_base::set_packet_param(uint32_t cmd, uint32_t id) -{ - pack_cmd_ = cmd; - pack_id_ = id; -} -int packet_data_base::get_packet_command(void) -{ - return pack_cmd_; -} -int packet_data_base::get_packet_id(void) -{ - return pack_id_; -} - -void packet_data_base::set_progress_notify(PROGRESS_NOTIFYER notify) -{ - progress_notify_ = notify; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -data_holder::data_holder() -{} -data_holder::~data_holder() -{} - - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -empty_holer::empty_holer(uint64_t size) : size_(size), put_(0) -{} -empty_holer::~empty_holer() -{} - -int empty_holer::put_data(const void* data, uint32_t* size) -{ - if (*size >= size_ - put_) - { - *size -= size_ - put_; - put_ = size_; - } - else - { - put_ += *size; - } - notify_progress(size_, put_, 0); - - return 0; -} -bool empty_holer::is_complete(void) -{ - return size_ == put_; -} -uint32_t empty_holer::get_required(void) -{ - return size_ - put_; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -file_saver::file_saver(void) : size_(0), wrote_(0), path_(""), check_(""), dst_(nullptr), pack_cmd_(0), pack_id_(0) -{} -file_saver::~file_saver() -{ - close(); -} - -void file_saver::close(void) -{ - if(dst_) - fclose(dst_); - dst_ = nullptr; - - size_ = wrote_ = pack_cmd_ = pack_id_ = 0; - path_ = check_ = ""; -} - -int file_saver::open(const char* path, uint64_t size, const char* check) -{ - int err = 0; - - close(); - dst_ = fopen(path, "wb"); - if(dst_) - { - uint64_t space = 0; - - err = sys_util::get_disk_size(path, nullptr, &space, nullptr); - if (err || space < size * 1.5) - { - fclose(dst_); - dst_ = nullptr; - remove(path); - if (err == 0) - err = ENOSPC; - } - else - { - path_ = path; - size_ = size; - check_ = check ? check : ""; - } - } - else - { - err = errno; - } - - return err; -} - -int file_saver::put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) -{ - if(!dst_) - return ENOENT; - - int w = *size > size_ - wrote_ ? size_ - wrote_ : *size, - real_w = fwrite(data, 1, w, dst_), // should handle error here ! - err = 0; - - *size = real_w; - wrote_ += real_w; - if(wrote_ >= size_) - { - fclose(dst_); - dst_ = nullptr; - } - else if (real_w < w) // what happens ? - { - err = ferror(dst_); - } - notify_progress(size_, wrote_, err); - - return 0; -} -bool file_saver::is_complete(void) -{ - return wrote_ >= size_; -} -uint32_t file_saver::get_required(void) -{ - return size_ - wrote_; -} - - - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -data_source::data_source() -{} -data_source::~data_source() -{} - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// dyn_mem -uint64_t dyn_mem::mem_used_bytes_ = 0; -MUTEX dyn_mem::mem_lock_; - - dyn_mem::dyn_mem(size_t size) : buf_(nullptr), len_(0), space_(ALIGN_INT(size, 16)) - { - buf_ = (uint8_t*)malloc(space_); - if(buf_) - { - LOCKER l(dyn_mem::mem_lock_); - dyn_mem::mem_used_bytes_ += space_; - memset(buf_, 0, space_); - } - } - dyn_mem::dyn_mem(void* buf, size_t size) : buf_((uint8_t*)buf), space_(size), len_(size) - { - - } - -dyn_mem::~dyn_mem() -{ - if(buf_) - { - free(buf_); - { - LOCKER l(dyn_mem::mem_lock_); - dyn_mem::mem_used_bytes_ -= space_; - } - } -} - -uint64_t dyn_mem::mem_used(void) -{ - return dyn_mem::mem_used_bytes_; -} - dyn_mem_ptr dyn_mem::memory(size_t size) - { - return new dyn_mem(size); - } - -uint32_t dyn_mem::space(void) -{ - return space_; -} -bool dyn_mem::set_len(size_t len) -{ - if(len > space_) - return false; - - len_ = len; - - return true; -} -int dyn_mem::put(const void* data, int len) -{ - if(len + len_ > space_) - len = space_ - len; - - if(len > 0) - { - memcpy(buf_ + len_, data, len); - len_ += len; - } - else - len = 0; - - return len; -} -void* dyn_mem::detach(size_t* size) -{ - void* buf = buf_; - - if (size) - *size = space_; - space_ = len_ = 0; - buf_ = nullptr; - - return buf; -} - -size_t dyn_mem::used(size_t len) -{ - if(len >= len_) - { - len_ = 0; - } - else if(len) - { - memcpy(buf_, buf_ + len, len_ - len); - len_ -= len; - } - - return len_; -} -dyn_mem& dyn_mem::operator+=(dyn_mem& r) -{ - if(len_ + r.get_rest() > space_) - { - size_t size = ALIGN_INT(len_ + r.get_rest(), 16); - uint8_t *buf = (uint8_t*)malloc(size); - memcpy(buf, buf_, len_); - free(buf_); - buf_ = buf; - { - LOCKER l(dyn_mem::mem_lock_); - dyn_mem::mem_used_bytes_ += size - space_; - } - space_ = size; - } - memcpy(buf_ + len_, r.buf_, r.get_rest()); - len_ += r.get_rest(); - - return *this; -} - -bool dyn_mem::is_memory_block(void) -{ - return true; -} -uint32_t dyn_mem::get_rest(void) -{ - return len_; -} - -// following API valid when is_memory_block() return true -uint8_t* dyn_mem::ptr(void) -{ - return buf_; -} - -// following API valid when is_memory_block() return false -int dyn_mem::fetch_data(void* buf, uint32_t* size) -{ - if(*size >= len_) - { - memcpy(buf, buf_, len_); - *size = len_; - len_ = 0; - } - else - { - memcpy(buf, buf_, *size); - used(*size); - } - - return 0; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -file_reader::file_reader() : len_(0), src_(nullptr), path_(""), consume_(0) -{} -file_reader::~file_reader() -{ - if(src_) - fclose(src_); -} - -int file_reader::open(const char* file) -{ - if(src_) - fclose(src_); - - src_ = fopen(file, "rb"); - if(!src_) - return errno; - - FSEEK(src_, 0, SEEK_END); - len_ = FTELL(src_); - FSEEK(src_, 0, SEEK_SET); - path_ = file; - consume_ = 0; - - return 0; -} -int file_reader::attach(FILE* f) -{ - if (src_) - { - fclose(src_); - src_ = nullptr; - } - - uint64_t cur = FTELL(f); - - FSEEK(f, 0, SEEK_END); - len_ = FTELL(f); - FSEEK(f, cur, SEEK_SET); - if (len_ <= cur) - return EINVAL; - - src_ = f; - len_ -= cur; - consume_ = 0; - - return 0; -} -FILE* file_reader::detach(void) -{ - FILE* ret = src_; - - src_ = nullptr; - len_ = 0; - path_ = ""; - - return ret; -} - -bool file_reader::is_memory_block(void) -{ - return false; -} -uint32_t file_reader::get_rest(void) -{ - return len_ - consume_; -} - -// following API valid when is_memory_block() return true -uint8_t* file_reader::ptr(void) -{ - return nullptr; -} - -// following API valid when is_memory_block() return false -int file_reader::fetch_data(void* buf, uint32_t* size) -{ - if (!src_) - return ENODATA; - - size_t r = fread(buf, 1, *size, src_); // fix me if ERROR occurs !!! - - consume_ += r; - *size = r; - if (consume_ >= len_) - { - fclose(src_); - src_ = nullptr; - } - notify_progress(len_, consume_, 0); - - return 0; -} diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/data.h b/device/gxx-linux/testusb/usb-rk3399/src/common/data.h deleted file mode 100644 index 53fc191..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/data.h +++ /dev/null @@ -1,232 +0,0 @@ -#pragma once - -// Objects IO -// -// created on 2023-03-10 - -#include "referer.h" -#include "packet.h" - -#include -#include - -#define CLS_PTR(cls) typedef cls* cls##_ptr; - - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -/* packet parameter keeper, parameter of corresponding packet -*/ -#define PROGRESS_NOTIFYER std::function - -class packet_data_base : public refer -{ - PROGRESS_NOTIFYER progress_notify_; - -protected: - uint32_t pack_cmd_; - uint32_t pack_id_; - -public: - packet_data_base(); - -protected: - virtual ~packet_data_base(); - int notify_progress(uint64_t total, uint64_t cur_size, uint32_t err); - -public: - void set_packet_param(uint32_t cmd, uint32_t id); - int get_packet_command(void); - int get_packet_id(void); - - void set_progress_notify(PROGRESS_NOTIFYER notify = PROGRESS_NOTIFYER()); -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -/* data_holder, used when data is also required for a certain packet -*/ -class data_holder : public packet_data_base -{ -public: - data_holder(); -protected: - virtual ~data_holder(); - -public: - virtual int put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) = 0; // return error code - virtual bool is_complete(void) = 0; - virtual uint32_t get_required(void) = 0; -}; - -class empty_holer : public data_holder -{ - uint64_t size_; - uint64_t put_; - -public: - empty_holer(uint64_t size); -protected: - ~empty_holer(); - - -public: - virtual int put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) override; // return error code - virtual bool is_complete(void) override; - virtual uint32_t get_required(void) override; -}; - -class file_saver : public data_holder -{ - uint64_t size_; - uint64_t wrote_; - std::string path_; - std::string check_; - FILE *dst_; - uint32_t pack_cmd_; - uint32_t pack_id_; - - void close(void); - -public: - file_saver(void); -protected: - ~file_saver(); - -public: - int open(const char* path, uint64_t size, const char* check = nullptr); - -public: - virtual int put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) override; - virtual bool is_complete(void) override; - virtual uint32_t get_required(void) override; -}; - - - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -/* data_source, can be a memory block or STREAM object -*/ -class data_source : public packet_data_base -{ - uint32_t pack_cmd_; - uint32_t pack_id_; - -public: - data_source(); - -protected: - virtual ~data_source(); - -public: - virtual bool is_memory_block(void) = 0; - virtual uint32_t get_rest(void) = 0; - - // following API valid when is_memory_block() return true - virtual uint8_t* ptr(void) = 0; - - // following API valid when is_memory_block() return false. return error code - virtual int fetch_data(void* buf, uint32_t* size) = 0; -}; - - -class dyn_mem : public data_source -{ - uint8_t* buf_; // data buf - size_t space_; // occupy space in bytes - size_t len_; // data length in bytes - - static MUTEX mem_lock_; - static uint64_t mem_used_bytes_; - -public: - dyn_mem(size_t size); - dyn_mem(void* buf, size_t size); - - static uint64_t mem_used(void); - static dyn_mem* memory(size_t size); - -protected: - ~dyn_mem(); - -public: - uint32_t space(void); - bool set_len(size_t len); - int put(const void* data, int len); - void* detach(size_t* size); // for constructed from dyn_mem(void* buf, size_t size) - - size_t used(size_t len); // used len bytes content, move following data to head and set data length, return rest data length - dyn_mem& operator+=(dyn_mem& r); - -public: - virtual bool is_memory_block(void) override; - virtual uint32_t get_rest(void) override; - - // following API valid when is_memory_block() return true - virtual uint8_t* ptr(void) override; - - // following API valid when is_memory_block() return false - virtual int fetch_data(void* buf, uint32_t* size) override; -}; - -class file_reader : public data_source -{ - size_t len_; - size_t consume_; - FILE *src_; - std::string path_; - -public: - file_reader(); - -protected: - ~file_reader(); - -public: - int open(const char* file); - int attach(FILE* f); - FILE* detach(void); - -public: - virtual bool is_memory_block(void) override; - virtual uint32_t get_rest(void) override; - - // following API valid when is_memory_block() return true - virtual uint8_t* ptr(void) override; - - // following API valid when is_memory_block() return false - virtual int fetch_data(void* buf, uint32_t* size) override; -}; - -CLS_PTR(packet_data_base); -CLS_PTR(data_holder); -CLS_PTR(data_source); -CLS_PTR(dyn_mem); -CLS_PTR(file_reader); - - -// callback proto -// -// parameters: usb_functionfs_event* - the function event ptr -// -// dyn_mem_ptr - the packet buffer, read-only -// -// uint32_t* - to return how many data in bytes the handler consumed -// -// normally, the value should be PACK_BASE::payload_len, i.e. the handler consume all data of an entire packet -// -// when invalid packet, suggest use the entire data -// -// packet_data_base_ptr* - return data_holder or data_source or nullptr -// -// data_holder: the packet/command need more data than dyn_mem_ptr provides to complete the business. such as 'write a large file' -// -// data_source: the reply content may be a large data (a large file content) -// -// return value of all routines is the reply packet, nullptr if the packet need not reply -// -#define FUNCTION_PROTO_COMMAND_HANDLE dyn_mem_ptr(dyn_mem_ptr, uint32_t* /*used*/, packet_data_base_ptr* /*The number of bytes required for this packet, 0 is over for this packet*/) - diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/event_monitor.cpp b/device/gxx-linux/testusb/usb-rk3399/src/common/event_monitor.cpp deleted file mode 100644 index 657f3b1..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/event_monitor.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include "event_monitor.h" - -// #define __USE_GNU // for gettid of including file 'bits/unistd_ext.h' - -#include /* nonblocking */ -#include /*setrlimit */ -#include -#include -#include -#include -#include -#include -// #include // for gettid -#include -#include -#include - -#include "log_util.h" - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// event_handler -event_handler::event_handler() -{} -event_handler::~event_handler() -{} - - - - - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// parent_holder -parent_holder::parent_holder() -{} -parent_holder::~parent_holder() -{} - - - - - - - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// linux - epoll wrapper ... -class epoll_wrapper : public event_monitor -{ - int32_t epoll_fd_; - int32_t quit_fd_[2]; - volatile bool run_; - std::vector threads_; - - static int32_t epoll_max; - - void clear_threads(void) - { - if(threads_.size()) - { - for (size_t i = 0; i < threads_.size(); ++i) - { - if (threads_[i]->joinable()) - threads_[i]->join(); - threads_[i].reset(); - } - threads_.clear(); - } - } - void close_monitor_fd(void) - { - if (epoll_fd_ != -1) - close(epoll_fd_); - epoll_fd_ = -1; - } - void clear(void) - { - clear_threads(); - close_monitor_fd(); - } - void monitor_thread(void) - { - log_cls::log(LOG_LEVEL_DEBUG, "monitor thread(%p) of object(%p) is working ...\n", gettid(), this); - while (run_) - { - struct epoll_event evs; - - memset(&evs, 0, sizeof(evs)); - if (epoll_wait(epoll_fd_, &evs, 1, -1) == -1) - continue; - if (evs.events == EPOLLOUT && evs.data.fd == quit_fd_[1]) - break; - - if (evs.events == EPOLLIN) - ((event_handler*)evs.data.ptr)->on_event(event_handler::EVENT_READ, nullptr, 0); - else if (evs.events == EPOLLOUT) - ((event_handler*)evs.data.ptr)->on_event(event_handler::EVENT_WRITE, nullptr, 0); - else - ; - } - log_cls::log(LOG_LEVEL_DEBUG, "monitor thread(%p) of object(%p) finished working.\n", gettid(), this); - } - -protected: - virtual ~epoll_wrapper() - { - stop(); - } - -public: - epoll_wrapper(const char* desc) : event_monitor(desc), epoll_fd_(-1), run_(true) - { - memset(quit_fd_, -1, sizeof(quit_fd_)); - } - -public: - virtual int32_t start(int32_t threads = 1) override - { - int32_t ret = stop(); - struct rlimit rt; - - rt.rlim_max = rt.rlim_cur = epoll_wrapper::epoll_max; - if (ret == 0 && setrlimit(RLIMIT_NOFILE, &rt) == 0) - { - epoll_fd_ = epoll_create(epoll_wrapper::epoll_max); - if (epoll_fd_ == -1) - { - ret = errno; - log_cls::log(LOG_LEVEL_FATAL, "epoll_create for '%s' failed: %s\n", desc_.c_str(), strerror(ret)); - } - else - { - run_ = true; - for (size_t i = 0; i < (size_t)threads; ++i) - { - THREAD_PTR t;//(new std::thread(&epoll_wrapper::monitor_thread, this)); - t.reset(new std::thread(&epoll_wrapper::monitor_thread, this)); - threads_.push_back(t); - } - } - } - else - { - log_cls::log(LOG_LEVEL_FATAL, "setrlimit for '%s-epoll' failed: %s\n", desc_.c_str(), strerror(ret)); - } - - return ret; - } - virtual int32_t stop(void) override - { - if(threads_.size()) - { - struct epoll_event ev; - #ifdef __USE_GNU - pipe2(quit_fd_, O_NONBLOCK); - #else - pipe(quit_fd_); - #endif - - log_cls::log(LOG_LEVEL_DEBUG, "quit fd[0] = %p, fd[1] = %p\n", quit_fd_[0], quit_fd_[1]); - - run_ = false; - ev.data.fd = quit_fd_[1]; - ev.events = EPOLLOUT | EPOLLET | EPOLLONESHOT; - for(size_t i = 0; i < threads_.size(); ++i) - epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, ev.data.fd, &ev); - clear_threads(); - close(quit_fd_[0]); - close(quit_fd_[1]); - memset(quit_fd_, -1, sizeof(quit_fd_)); - } - - close_monitor_fd(); - - return 0; - } - - virtual int32_t add_fd(event_handler* handler) override - { - struct epoll_event ev; - int32_t ret = -1; - - if (!handler || handler->get_fd() == -1) - return EINVAL; - - if (epoll_fd_ == -1) - return EFAULT; - - handler->add_ref(); // add ref for epoll_event holder ... - ev.data.ptr = handler; - ev.events = EPOLLIN | EPOLLOUT | EPOLLET; // EPOLLONESHOT | EPOLLHUP - ret = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, handler->get_fd(), &ev); - if (ret == -1) - { - ret = errno; - log_cls::log(LOG_LEVEL_FATAL, "add fd(%d) to %s-epoll failed: %s\n", handler->get_fd(), desc_.c_str(), strerror(ret)); - handler->release(); - } - - return ret; - } - virtual int32_t remove_fd(event_handler* handler) override - { - struct epoll_event ev; - int32_t ret = -1; - - if (!handler || handler->get_fd() == -1) - return EINVAL; - - if (epoll_fd_ == -1) - return EFAULT; - - ev.data.ptr = handler; - ev.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLHUP; // EPOLLONESHOT - ret = epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, handler->get_fd(), &ev); - - if (ret == 0) - { - // ENOENT returned if object 'handler' has not registered, so we can free it here when success in EPOLL_CTL_DEL ... - handler->release(); - } - else - { - ret = errno; - log_cls::log(LOG_LEVEL_FATAL, "remove fd(%d) from %s-epoll failed: %s\n", handler->get_fd(), desc_.c_str(), strerror(ret)); - } - - return ret; - } -}; -int32_t epoll_wrapper::epoll_max = 100; - - - - - - - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// event_handler -event_monitor::event_monitor(const char* desc) : desc_(desc ? desc : "") -{ - log_cls::log(LOG_LEVEL_DEBUG, "+event_monitor(%p) of '%s' contructing ...\n", this, desc_.c_str()); -} -event_monitor::~event_monitor() -{ - log_cls::log(LOG_LEVEL_DEBUG, "-event_monitor(%p) of '%s' destroyed\n", this, desc_.c_str()); -} - -event_monitor* event_monitor::create(const char* desc, int32_t type) -{ - if (type == EV_TYPE_EPOLL) - return dynamic_cast(new epoll_wrapper(desc)); - else - return nullptr; -} diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/event_monitor.h b/device/gxx-linux/testusb/usb-rk3399/src/common/event_monitor.h deleted file mode 100644 index 2a77a29..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/event_monitor.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once - -// event monitor -// -// created on 2022-11-29 -// - -#include "referer.h" -#include "packet.h" - -#include -#include - -typedef std::shared_ptr THREAD_PTR; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// event definition ... -enum scanner_event -{ - SCANNER_EVENT_NONE = 0, - - // 1 - IPC - SCANNER_EVENT_IPC_DATA_RECEIVED = 1, - SCANNER_EVENT_IPC_DATA_SENT, - - // 2 - image-collector - SCANNER_EVENT_COLLECTOR_WORKING = 100, // on_event(, nullptr, 0), the first message after start success - - // normal image, double feeding image, jammed image, stapled imge, size-check error image ... - SCANNER_EVENT_COLLECTOR_IMG_DATA, // on_event(, (LPIMGD)data, bytes of data), image data transfer, buffer can be re-used when return - - SCANNER_EVENT_COLLECTOR_PAPER_ON, // on_event(, (bool*)paper_on, (bool)local_display) - SCANNER_EVENT_COLLECTOR_COVER_OPENNED, // on_event(, (bool*)openned, (bool)local_display) - SCANNER_EVENT_COLLECTOR_SLEEPPING, // on_event(, (bool*)sleepping, (bool)local_display) - SCANNER_EVENT_COLLECTOR_ERROR, // on_event(, (char*)err-msg, (bool)local_display), used when unknown fatal error occurs! - - SCANNER_EVENT_COLLECTOR_STOPPED, // on_event(, (char*)err-msg, (size_t)err-code), the last message after start success - - // 3 - image-process - SCANNER_EVENT_IMAGE_PROC_FINAL_BUF = 200, // on_event(, (void**)buf, (size_t)len), get buffer for store the final image - SCANNER_EVENT_IMAGE_PROC_OK, // on_event(, ) - SCANNER_EVENT_IMAGE_PROC_ERR, - - // 4 - resource - SCANNER_EVENT_RESOURCE_LOW_MEM = 300, // on_event(, (bool*)low_mem, (bool)local_display) - SCANNER_EVENT_RESOURCE_LOW_DISK, // on_event(, (bool*)low_disk, (bool)local_display) - SCANNER_EVENT_RESOURCE_HIGH_CPU, // on_event(, (bool*)high_cpu, (bool)local_display) -}; - -typedef struct _img_data -{ - LPPACKIMAGE info; - uint8_t* data; -}IMGD, *LPIMGD; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// object event_handler -// -// derived from 'event_handler' if your class will handle some events of drived by events -// -class event_handler : public refer -{ -protected: - event_handler(); - virtual ~event_handler(); - -public: - virtual int32_t on_event(int32_t ev, void* data, size_t data_len) = 0; - virtual int32_t get_fd(void) = 0; - - enum - { - EVENT_READ = 0, - EVENT_WRITE, - }; -}; - -class parent_holder : public refer -{ -protected: - parent_holder(); - virtual ~parent_holder(); - -public: - virtual int32_t stop(void) = 0; // stop work and release parent ptr -}; - -// event_monitor to manage an event-driven model, this will trigger EVENT_READ/EVENT_WRITE events to 'handler' -// -class event_monitor : public refer -{ -protected: - std::string desc_; - -protected: - event_monitor(const char* desc); - virtual ~event_monitor(); - -public: - virtual int32_t start(int32_t threads = 1) = 0; - virtual int32_t stop(void) = 0; - - virtual int32_t add_fd(event_handler* handler) = 0; - virtual int32_t remove_fd(event_handler* handler) = 0; - - enum - { - EV_TYPE_POLL = 1, - EV_TYPE_EPOLL, - }; - static event_monitor* create(const char* desc, int32_t type = EV_TYPE_EPOLL); -}; - -class sane_cfg_provider : public refer -{ -public: - sane_cfg_provider() - {} - virtual ~sane_cfg_provider() - {} - -public: - // Function: get all or given name configuration value - // - // Parameters: buf - to receive the configuration value or all configuration JSON - // - // len - [in] bytes of 'buf', [out] - content bytes in 'buf', or minimum size needed - // - // cfg_name - given configuration name, if set, put current value of the configuration in 'buf', - // or put all configurations JSON text in 'buf' if was nullptr. refer to SANE-config - // - // Return: 0 - on success - // EINVAL - if paramter 'len' was nullptr - // ENOMEM - if size of 'buf' was too small, the minimum size needed is stored in 'len' - // ENOENT - the configuration named 'cfg_name' has not found - virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr) = 0; - - // Function: set value of configuration named 'cfg_name' - // - // Parameters: cfg_name - the configuration name - // - // data - the value address, nullptr is for restore to default value - // (bool*), (int*), (double*), (char*) - // - // len - bytes in 'data' - // - // Return: 0 - on success - // EINVAL - parameter was invalid. 'cfg_name' was nullptr - // ENOENT - configuration 'cfg_name' was not found - // EUCLEAN - content in 'data' was not exact, the exact value is stored in 'data', and bytes in 'len' - virtual int32_t set_config(const char* cfg_name, void* data, size_t* len) = 0; -}; - diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_util.cpp b/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_util.cpp deleted file mode 100644 index acbbcfc..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_util.cpp +++ /dev/null @@ -1,472 +0,0 @@ -#include "ipc_util.h" - -#if !defined(WIN32) && !defined(_WIN64) -#include -#include -#include -#include -#include -#endif - -#include - -#include "log_util.h" -#include "sys_util.h" - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// linux_event -unsigned long linux_event::to_abs_time_us = 0; - -linux_event::linux_event(const char* desc) : waiting_(false), sem_(nullptr), desc_(desc ? desc : ""), first_(true), multi_proc_(false) -{ - log_cls::log(LOG_LEVEL_ALL, "+linux_event(%p) unamed for '%s' constructing ...\n", this, desc_.c_str()); - -#if defined(WIN32) || defined(_WIN64) - err_ = 0; - local_sem_ = CreateEventA(NULL, TRUE, FALSE, NULL); -#else - err_ = sem_init(&local_sem_, 0, 0); -#endif - - if (err_ == -1) - { - err_ = errno; - log_cls::log(LOG_LEVEL_FATAL, " %p: sem_init = %s\n", this, strerror(err_)); - } - else - { - sem_ = &local_sem_; - } -} -linux_event::linux_event(const char* name, const char* desc) : waiting_(false), sem_(nullptr), desc_(desc ? desc : ""), first_(true), multi_proc_(true) -{ - log_cls::log(LOG_LEVEL_ALL, "+linux_event(%p) of named '%s' for '%s' constructing ...\n", this, name, desc_.c_str()); -#if defined(WIN32) || defined(_WIN64) - local_sem_ = CreateEventA(NULL, TRUE, FALSE, name); - sem_ = &local_sem_; - if(local_sem_ == NULL) -#else - sem_ = sem_open(name, O_CREAT | O_EXCL, 0777, 0); - if (sem_ == (sem_t*)SEM_FAILED) -#endif - { - sem_ = nullptr; - err_ = errno; - log_cls::log(LOG_LEVEL_FATAL, " %p: sem_open(O_CREAT | O_EXCL) = %s\n", this, strerror(err_)); - if(err_ = EEXIST) - { -#if defined(WIN32) || defined(_WIN64) - local_sem_ = OpenEventA(EVENT_ALL_ACCESS, FALSE, name); - if(local_sem_ == NULL) -#else - sem_ = sem_open(name, 0666); - if (sem_ == (sem_t*)SEM_FAILED) -#endif - { - err_ = errno; - sem_ = nullptr; - log_cls::log(LOG_LEVEL_FATAL, " %p: sem_open = %s\n", this, strerror(err_)); - } - else - { - err_ = 0; - first_ = false; - } - } - } - else - { - name_ = name; - log_cls::log(LOG_LEVEL_DEBUG, " %p: created named sem OK.\n", this); -#if !defined(WIN32) && !defined(_WIN64) - err_ = sem_init(sem_, 1, 0); // this is used to initialize the event count, whether named or unamed - if (err_ == -1) - { - err_ = errno; - log_cls::log(LOG_LEVEL_FATAL, " %p: sem_init = %s\n", this, strerror(err_)); - sem_close(sem_); - sem_ = nullptr; - sem_unlink(name); - } -#endif - } -} -linux_event::linux_event(sem_t* mem_sem, bool first, const char* desc) : waiting_(false), sem_(mem_sem), desc_(desc ? desc : ""), first_(first), multi_proc_(true) -{ - log_cls::log(LOG_LEVEL_ALL, "+linux_event(%p) at mem(%p) for '%s' constructing ...\n", this, mem_sem, desc_.c_str()); - - if(first) - { -#if defined(WIN32) || defined(_WIN64) - sem_ = mem_sem; -#else - err_ = sem_init(sem_, 1, 0); -#endif - if (err_ == -1) - { - err_ = errno; - log_cls::log(LOG_LEVEL_FATAL, " %p: sem_init = %s\n", this, strerror(err_)); - } - } -} -linux_event::~linux_event() -{ - if (sem_) - { - char ptr[40] = {0}; - std::string tips(""); - - sprintf(ptr, " ~%p: ", this); - tips = ptr; - if(sem_ == &local_sem_ || (first_ && name_.empty())) - { -#if defined(WIN32) || defined(_WIN64) - CloseHandle(local_sem_); - local_sem_ = NULL; -#else - err_ = log_cls::log_when_err(sem_destroy(sem_), (tips + "sem_destroy").c_str()); - } - else - { - err_ = log_cls::log_when_err(sem_close(sem_), (tips + "sem_close").c_str()); - - // else // why not else ? we should ensure delete the kernel object when unused. - if(!name_.empty()) // i am the named object owner ! - { - err_ = log_cls::log_when_err(sem_unlink(name_.c_str()), (tips + "sem_unlink").c_str(), LOG_LEVEL_FATAL); // This will cause previously opened objects to never receive events, even if you reopen it. - } -#endif - } - } - log_cls::log(LOG_LEVEL_ALL, "-linux_event(%p) destroyed.\n", this); -} - -int32_t linux_event::clear_named_event(const char* name) -{ - int32_t err = 0; - -#if !defined(WIN32) && !defined(_WIN64) - sem_t* sem = sem_open(name, O_CREAT | O_EXCL, 0777, 0); - - if(sem == (sem_t*)SEM_FAILED) - { - if(errno == EEXIST) - { - err = sem_unlink(name); - if(err == -1) - err = errno; - } - else - { - return 0; - } - } - else - { - sem_close(sem); - sem_unlink(name); - } -#endif - - return err; -} - void linux_event::reset_calc_abs_time(unsigned us) - { - if(us == -1) - { - TIMEV now = {0}, after = {0}; - struct timespec abst = {0}; - - linux_event::to_abs_time_us = 10; - if(chronograph::now(&now)) - { - abst.tv_sec = now.tv_sec; - abst.tv_nsec = USEC_2_NS(now.tv_usec); - abst.tv_nsec += MSEC_2_NS(1) + linux_event::to_abs_time_us; - - // overflow ... - abst.tv_sec += abst.tv_nsec / SEC_2_NS(1); - abst.tv_nsec %= SEC_2_NS(1); - if(chronograph::now(&after)) - { - if(after.tv_usec > now.tv_usec) - linux_event::to_abs_time_us = after.tv_usec - now.tv_usec; - else - linux_event::to_abs_time_us = SEC_2_US(1) + after.tv_usec - now.tv_usec; - } - } - } - else - { - linux_event::to_abs_time_us = us; - } - } -bool linux_event::abs_time_after(struct timespec* abstm, unsigned ms) -{ - TIMEV now = {0}; - - if(!chronograph::now(&now)) - { - log_cls::log(LOG_LEVEL_FATAL, "gettimeofday faied: %s\n!", strerror(errno)); - time(&now.tv_sec); - } - abstm->tv_sec = now.tv_sec; - abstm->tv_nsec = USEC_2_NS(now.tv_usec); - abstm->tv_nsec += MSEC_2_NS(ms) + USEC_2_NS(linux_event::to_abs_time_us); - - // overflow ... - abstm->tv_sec += abstm->tv_nsec / SEC_2_NS(1); - abstm->tv_nsec %= SEC_2_NS(1); - - return true; -} - -bool linux_event::is_ready(void) -{ - return sem_ != nullptr; -} -bool linux_event::is_named_first(void) -{ - return !name_.empty(); -} -bool linux_event::wait_try(void) -{ -#if defined(WIN32) || defined(_WIN64) - return WaitForSingleObject(*sem_, 0) == WAIT_OBJECT_0; -#else - return sem_trywait(sem_) == 0; -#endif -} -bool linux_event::wait(unsigned timeout) -{ - bool waited = true; - - //log_cls::log(LOG_LEVEL_ALL, "linux_event(%p): waiting(%u) ...\n", this, timeout); - waiting_ = true; -#if defined(WIN32) || defined(_WIN64) - waited = WaitForSingleObject(*sem_, timeout) == WAIT_OBJECT_0; -#else - if (timeout == WAIT_INFINITE) - { - sem_wait(sem_); - } - else - { - struct timespec to = {0}; - - linux_event::abs_time_after(&to, timeout); - waited = sem_timedwait(sem_, &to) == 0; - } -#endif - waiting_ = false; - //log_cls::log(LOG_LEVEL_ALL, "linux_event(%p): waited(%u) = %d\n", this, timeout, waited); - - return waited; -} -void linux_event::trigger(void) -{ -#if defined(WIN32) || defined(_WIN64) - err_ = 0; - SetEvent(*sem_); -#else - err_ = sem_post(sem_); -#endif - - if(err_) - err_ = errno; - - //log_cls::log(LOG_LEVEL_ALL, "linux_event(%p): trigger = %s\n", this, err_ == 0 ? "OK" : strerror(errno)); -} -void linux_event::reset(void) -{ -#if defined(WIN32) || defined(_WIN64) - err_ = 0; - ResetEvent(*sem_); -#else - err_ = sem_init(sem_, multi_proc_, 0); -#endif - - if(err_) - err_ = errno; - - //log_cls::log(LOG_LEVEL_ALL, "linux_event(%p): reset = %s\n", this, err_ == 0 ? "OK" : strerror(errno)); -} -bool linux_event::is_waiting(void) -{ - return waiting_; -} - - - - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// shared_mem -#if !defined(WIN32) && !defined(_WIN64) -uint64_t shared_mem::mem_total_ = 0; -uint64_t shared_mem::page_unit_ = 0; -uint64_t shared_mem::huge_page_unit_ = 0; - - -shared_mem::shared_mem() : name_(""), id_(0), size_(0), shm_buf_(shared_mem::invalid_map_addr()), first_(false), shm_id_(-1) -{ - if (shared_mem::page_unit_ == 0) - shared_mem::init_page_info(); - - log_cls::log(LOG_LEVEL_ALL, "+shared_mem(%p) constructed, page size = %ld\n", this, page_unit_); -} -shared_mem::~shared_mem() -{ - close(); - log_cls::log(LOG_LEVEL_ALL, "-shared_mem(%p) destroyed.\n", this); -} - -void shared_mem::init_page_info(void) -{ - shared_mem::page_unit_ = sys_util::get_page_size(); - - // Hugepagesize: 2048 kB - if(sys_util::get_inf_file_data("/proc/meminfo", 80, "MemTotal: %ld", &shared_mem::mem_total_)) - shared_mem::mem_total_ *= 1024; - if(sys_util::get_inf_file_data("/proc/meminfo", 80, "Hugepagesize: %ld", &shared_mem::huge_page_unit_)) - shared_mem::huge_page_unit_ *= 1024; - - log_cls::log(LOG_LEVEL_DEBUG, "TotalMemory: %s, system page size: %s, huge page size %s\n" - , sys_util::format_readable_bytes(shared_mem::mem_total_).c_str() - , sys_util::format_readable_bytes(shared_mem::page_unit_).c_str() - , sys_util::format_readable_bytes(shared_mem::huge_page_unit_).c_str()); -} -char* shared_mem::invalid_map_addr(void) -{ - return (char*)-1; -} - -int32_t shared_mem::open(int32_t id, size_t* bytes, const char* name) -{ - key_t key = (key_t)-1; // ftok(name, id); - int32_t ret = close(); - size_t size = bytes ? *bytes : 0; - std::string pe(""); - - if (ret) - return ret; - - if(!name || *name == 0) - { - pe = sys_util::get_module_path(); - name = pe.c_str(); - } - key = ftok(name, id); - if (key == (key_t)-1) - { - log_cls::log(LOG_LEVEL_FATAL, "shared_memory(%p): ftok('%s', %d) = %s\n", this, name, id, strerror(errno)); - - return errno; - } - log_cls::log(LOG_LEVEL_DEBUG, "shared memory key: %p\n", key); - - size = ALIGN_INT(size, shared_mem::page_unit_); - if (!bytes || *bytes != size) - { - log_cls::log(LOG_LEVEL_DEBUG, "add %ld upto multiple of page size: %ld\n", bytes ? *bytes : 0, size); - if (bytes) - *bytes = size; - } - - shm_id_ = shmget(key, size, IPC_EXCL | IPC_CREAT | 0600); - if (shm_id_ == -1) - { - ret = errno; - log_cls::log(LOG_LEVEL_WARNING, "%p: create shared memory('%s', %d) failed: %s\n", this, name, id, strerror(ret)); - if (ret == EEXIST) - { - shm_id_ = shmget(key, size, 0600); - if (shm_id_ == -1) - { - ret = errno; - log_cls::log(LOG_LEVEL_WARNING, "%p: open shared memory('%s', %d) failed: %s\n", this, name, id, strerror(ret)); - } - else - { - ret = 0; - first_ = false; - } - } - } - else // i created the shared memory ... - { - first_ = true; - } - - if (ret == 0) - { - shm_buf_ = (char*)shmat(shm_id_, nullptr, 0); - if (shm_buf_ == shared_mem::invalid_map_addr()) - { - ret = errno; - log_cls::log(LOG_LEVEL_WARNING, "%p: shmat failed: %s\n", this, strerror(ret)); - close(); - } - else - { - log_cls::log(LOG_LEVEL_DEBUG, "%p: %s shared memory('%s', %d) at %p(+%s) OK.\n", this, first_ ? "create" : "open", name, id, shm_buf_, sys_util::format_readable_bytes(size).c_str()); - name_ = name; - id_ = id; - size_ = size; - } - } - - return ret; -} -int32_t shared_mem::close(void) -{ - int32_t ret = 0; - - if (shm_buf_ != shared_mem::invalid_map_addr()) - { - ret = log_cls::log_when_err(shmdt(shm_buf_), "shmdt"); - if (ret) - return ret; - - shm_buf_ = shared_mem::invalid_map_addr(); - } - if (first_ && shm_id_ >= 0) - { - ret = log_cls::log_when_err(shmctl(shm_id_, IPC_RMID, nullptr), "shmctrl(IPC_RMID)"); - if (ret && ret != ENOENT) - { - // re-map buffer ... - shm_buf_ = (char*)shmat(shm_id_, nullptr, 0); - - return ret; - } - - shm_id_ = -1; - } - - name_ = ""; - id_ = 0; - first_ = false; - size_ = 0; - - return ret; -} - -char* shared_mem::get_mem(size_t* size) -{ - if (size) - *size = size_; - - return shm_buf_ == shared_mem::invalid_map_addr() ? nullptr : shm_buf_; -} -bool shared_mem::is_first(void) -{ - return first_; -} - -void shared_mem::clear_kernel_object(void) -{ - log_cls::log_when_err(shmctl(shm_id_, IPC_RMID, nullptr), "shmctrl(IPC_RMID)"); -} - -#endif \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_util.h b/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_util.h deleted file mode 100644 index 3949d58..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_util.h +++ /dev/null @@ -1,160 +0,0 @@ -#pragma once - -// IPC utility -// -// created on 2022-11-29 -// - - -#include "referer.h" -#if defined(WIN32) || defined(_WIN64) -#include -#define sem_t HANDLE -#define SEM_FAILED NULL -#else -#include -#endif -#include - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// object event -// -class linux_event : public refer -{ - int32_t err_; - sem_t local_sem_; - sem_t* sem_; - bool first_; - bool multi_proc_; - volatile bool waiting_; - std::string desc_; - std::string name_; - - static unsigned long to_abs_time_us; // used in sem_timedwait to calculate absolute time from elapse - -public: - linux_event(const char* desc); // to initialize a in-process object - linux_event(const char* name, const char* desc); // to initialize a multi-process object - linux_event(sem_t* mem_sem, bool first/*invoke sem_init when true*/, const char* desc); // to initialize an event at given memory (shared memory) - - static int32_t clear_named_event(const char* name); - static void reset_calc_abs_time(unsigned us = -1); // reset 'to_abs_time_us' value, -1 is for re-calc - static bool abs_time_after(struct timespec* abstm, unsigned ms); - -protected: - ~linux_event(); - -public: - bool is_ready(void); - bool is_named_first(void); // whether I created the named event - bool wait_try(void); - bool wait(unsigned timeout = WAIT_INFINITE/*ms*/); // WAIT_INFINITE is waiting unfinite, true when watied and false for wait timeout - void trigger(void); - void reset(void); // re-initialize. DANGEROUS !!! all wait operation before will not receive any event after this !!! - bool is_waiting(void); -}; - - -template -class safe_fifo -{ - MUTEX lock_; - std::deque que_; - linux_event* wait_; - -public: - safe_fifo() : wait_(new linux_event("fifo")) - {} - ~safe_fifo() - { - wait_->release(); - } - -public: - void save(const T& t, bool notify = false) - { - LOCKER lock(lock_); - - que_.push_back(std::move(t)); - if (notify) - wait_->trigger(); - } - bool take(T& t, bool wait = false) - { - if (wait && size() == 0) - { - wait_->wait(); - wait_->reset(); - } - - { - LOCKER lock(lock_); - - if (que_.size()) - { - t = std::move(que_.front()); - que_.pop_front(); - - return true; - } - else - { - return false; - } - } - } - size_t size(void) - { - LOCKER lock(lock_); - - return que_.size(); - } - void clear(void) - { - LOCKER lock(lock_); - - que_.clear(); - } - void quit(void) - { - wait_->trigger(); - } -}; - -#if !defined(WIN32) && !defined(_WIN64) - -class shared_mem : public refer -{ - std::string name_; - int32_t id_; - int32_t shm_id_; - char* shm_buf_; - size_t size_; - bool first_; - -public: - shared_mem(); - - static void init_page_info(void); - static char* invalid_map_addr(void); - - static uint64_t mem_total_; - static uint64_t page_unit_; - static uint64_t huge_page_unit_; - -protected: - ~shared_mem(); - -public: - int32_t open(int32_t id, size_t* bytes, const char* name = nullptr); - int32_t close(void); - - char* get_mem(size_t* size = nullptr); - bool is_first(void); - - void clear_kernel_object(void); -}; - -#endif diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_wrapper.cpp b/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_wrapper.cpp deleted file mode 100644 index 5c9fdac..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_wrapper.cpp +++ /dev/null @@ -1,373 +0,0 @@ -#include "ipc_wrapper.h" - -#include -#include - -#include "log_util.h" -#include "ipc_util.h" -#include "sys_util.h" - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// ipc_wrapper_shm -class ipc_wrapper_shm : public ipc_wrapper -{ - enum data_ind - { - DATA_INTER_CMD = 0, - }; - enum internal_cmd - { - INTER_CMD_NONE = 0, - INTER_CMD_EXIT, - }; - typedef struct _shm_pack - { - size_t space; // buffer length - size_t bytes; // data length - char data[4]; - }SHMPACK, *LPSHMPACK; - typedef struct _sync_shm // 1-lock(write_lock) --> 2-write content --> 3-notify read --> 4-wait(wait_sent) --> 5-return step 2 if data has not sent finished, or else to 6 --> 6-release(write_lock) --> 7-over - { - sem_t wait_arrive; // read event - sem_t wait_sent; // peer has read, i can re-write now - sem_t notify_read; // notify peer to read - sem_t notify_write; // notify peer to write - char data[8]; // internal data - }SYNCSHM, *LPSYNCSHM; - volatile bool run_; - MUTEX write_lock_; - int32_t id_; - shared_mem* shm_; - LPSYNCSHM sync_shm_; - linux_event* wait_arrive_; - linux_event* wait_sent_; - linux_event* notify_write_; - linux_event* notify_read_; - THREAD_PTR thread_; - LPSHMPACK buf_in_; - LPSHMPACK buf_out_; - bool buf_out_used_; - volatile bool cancel_write_; - - void create(const char* file, int32_t id, size_t bytes, unsigned sent_percent) - { - int32_t err = 0; - - shm_ = new shared_mem(); - err = shm_->open(id, &bytes, file); - if (err) - { - log_cls::log(LOG_LEVEL_FATAL, "ipc_wrapper_shm(%p) open shared memory(%s, %d, %s) failed: %s\n" - , this, file, id, sys_util::format_readable_bytes(bytes).c_str(), strerror(err)); - shm_->release(); - shm_ = nullptr; - - return; - } - - SHMPACK pack = { 0 }; - std::string desc("ipc_wrapper_shm-"); - char buf[80] = { 0 }, *ptr = shm_->get_mem(&pack.space); - int32_t pack_head = ALIGN_INT(sizeof(pack), 16), head = ALIGN_INT(sizeof(SYNCSHM), 16); - - sprintf(buf, "%d-", id); - desc += buf; - - sync_shm_ = (LPSYNCSHM)ptr; - ptr += head; - pack.space -= head + pack_head * 2; - head = ALIGN_INT(pack.space * sent_percent / 100, 16); - if (shm_->is_first()) - { - SYNCSHM ss; - - memcpy(sync_shm_, &ss, sizeof(ss)); - buf_in_ = (LPSHMPACK)ptr; - buf_in_->space = pack.space - head; - ptr += buf_in_->space + pack_head; - buf_out_ = (LPSHMPACK)ptr; - buf_out_->space = head; - //* - wait_arrive_ = new linux_event(&sync_shm_->wait_arrive, true, (desc + "wait_arrive").c_str()); - wait_sent_ = new linux_event(&sync_shm_->wait_sent, true, (desc + "wait_sent").c_str()); - notify_read_ = new linux_event(&sync_shm_->notify_read, true, (desc + "notify_read").c_str()); - notify_write_ = new linux_event(&sync_shm_->notify_write, true, (desc + "notify_write").c_str()); - /*/ - wait_arrive_ = new linux_event((desc + "wait_arrive").c_str(), ""); - wait_sent_ = new linux_event((desc + "wait_sent").c_str(), ""); - notify_write_ = new linux_event((desc + "notify_write").c_str(), ""); - notify_read_ = new linux_event((desc + "notify_read").c_str(), ""); - ///*//////////// - memset(sync_shm_->data, 0, sizeof(sync_shm_->data)); - } - else - { - //* - wait_sent_ = new linux_event(&sync_shm_->notify_write, false, (desc + "wait_sent").c_str()); - wait_arrive_ = new linux_event(&sync_shm_->notify_read, false, (desc + "wait_arrive").c_str()); - notify_write_ = new linux_event(&sync_shm_->wait_sent, false, (desc + "notify_write").c_str()); - notify_read_ = new linux_event(&sync_shm_->wait_arrive, false, (desc + "notify_read").c_str()); - /*/ - wait_arrive_ = new linux_event((desc + "notify_read").c_str(), ""); - wait_sent_ = new linux_event((desc + "notify_write").c_str(), ""); - notify_read_ = new linux_event((desc + "wait_arrive").c_str(), ""); - notify_write_ = new linux_event((desc + "wait_sent").c_str(), ""); - ///*//////////// - buf_out_ = (LPSHMPACK)ptr; - buf_in_ = (LPSHMPACK)(ptr + pack_head + buf_out_->space); - } - - thread_.reset(new std::thread(&ipc_wrapper_shm::read_thread, this)); - // handler_->on_event(event_handler::EVENT_WRITE, buf_out_->data, buf_size_); - } - void read_thread(void) - { - event_handler* handler = handler_; - - handler->add_ref(); - while (run_) - { - wait_arrive_->wait(); - if (!run_) - break; - if (!shm_->is_first() && sync_shm_->data[DATA_INTER_CMD] == INTER_CMD_EXIT) - break; - - handler->on_event(SCANNER_EVENT_IPC_DATA_RECEIVED, buf_in_->data, buf_in_->bytes); - notify_write_->trigger(); - } - handler->release(); - } - -public: - ipc_wrapper_shm(const char* file, int32_t id - , size_t bytes - , event_handler* handler - , unsigned sent_percent = 50) - : ipc_wrapper(handler), run_(true), shm_(nullptr), sync_shm_(nullptr) - , wait_arrive_(nullptr), wait_sent_(nullptr), notify_write_(nullptr), notify_read_(nullptr) - , buf_in_(nullptr), buf_out_(nullptr), id_(id), buf_out_used_(false), cancel_write_(false) - { - create(file, id, bytes, sent_percent); - } - -protected: - ~ipc_wrapper_shm() - {} - -public: - virtual int32_t write(const char* pack, size_t * bytes, bool kbuf, unsigned timeout = WAIT_INFINITE) override - { - if (!shm_) - return ENOTCONN; - - // invoke in read-thread is not allowed - if(std::this_thread::get_id() == thread_->get_id()) - return EDEADLOCK; - - LOCKER lock(write_lock_); - size_t rest = *bytes; - int32_t ret = 0; - - cancel_write_ = false; - if (kbuf) - { - buf_out_->bytes = rest; - notify_read_->trigger(); - if (wait_sent_->wait(timeout)) - rest = 0; - else - ret = ETIME; - } - else - { - chronograph timer; - while (rest) - { - buf_out_->bytes = rest > buf_out_->space ? buf_out_->space : rest; - memcpy(buf_out_->data, pack, buf_out_->bytes); - notify_read_->trigger(); - - pack += buf_out_->space; - if (!wait_sent_->wait(timeout)) - break; - if (cancel_write_) - break; - - if (rest <= buf_out_->space) - { - rest = 0; - break; - } - rest -= buf_out_->space; - - if (timeout) - { - uint64_t t = timer.elapse_ms(); - if (t >= timeout) - break; - - timeout -= t; - timer.reset(); - } - } - if (cancel_write_) - ret = ECANCELED; - else if (rest) - ret = ETIME; - } - *bytes -= rest; - - return ret; - } - virtual bool cancel_write(void) override - { - cancel_write_ = true; - if (wait_sent_->is_waiting()) - { - wait_sent_->trigger(); - wait_sent_->reset(); // sure ? - } - - return true; - } - virtual bool is_ok(void) override - { - return shm_ != nullptr; - } - virtual bool is_first(void) override - { - return shm_ && shm_->is_first(); - } - - virtual void* get_kbuf(size_t* bytes) override - { - if (!bytes) - return nullptr; - - if (buf_out_used_) - { - *bytes = 0; - - return nullptr; - } - - buf_out_used_ = true; - *bytes = buf_out_->space; - - return buf_out_->data; - } - virtual void release_kbuf(void* buf) override - { - buf_out_used_ = false; - } - virtual void clear_kernel_objects(void) override - { - std::string desc("ipc_wrapper_shm-"); - char id[20] = { 0 }; - - sprintf(id, "%d-", id_); - desc += id; - linux_event::clear_named_event((desc + "wait_arrive").c_str()); - linux_event::clear_named_event((desc + "wait_sent").c_str()); - linux_event::clear_named_event((desc + "notify_write").c_str()); - linux_event::clear_named_event((desc + "notify_read").c_str()); - - shm_->clear_kernel_object(); - } - virtual int32_t stop(void) override - { - run_ = false; - if (shm_) - { - wait_arrive_->trigger(); - if (thread_.get() && thread_->joinable()) - thread_->join(); - thread_.reset(); - - if (is_first()) - { - sync_shm_->data[DATA_INTER_CMD] = INTER_CMD_EXIT; - notify_read_->trigger(); - wait_sent_->wait(100); - } - notify_read_->release(); - notify_read_ = nullptr; - notify_write_->release(); - notify_write_ = nullptr; - wait_arrive_->release(); - wait_arrive_ = nullptr; - wait_sent_->release(); - wait_sent_ = nullptr; - sync_shm_ = nullptr; - buf_in_ = buf_out_ = nullptr; - - shm_->close(); - shm_->release(); - } - shm_ = nullptr; - - return ipc_wrapper::stop(); - } - -}; - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// ipc_wrapper -ipc_wrapper::ipc_wrapper(event_handler* handler) : handler_(handler) -{ - if (handler_) - handler_->add_ref(); -} -ipc_wrapper::~ipc_wrapper() -{} - -void* ipc_wrapper::get_kbuf(size_t* bytes) -{ - if (bytes) - *bytes = 0; - - return nullptr; -} -void ipc_wrapper::release_kbuf(void* buf) -{} -void ipc_wrapper::clear_kernel_objects(void) -{} -bool ipc_wrapper::cancel_write(void) -{ - return false; -} -int32_t ipc_wrapper::stop(void) -{ - if (handler_) - handler_->release(); - handler_ = nullptr; - - return 0; -} - -ipc_wrapper* ipc_wrapper::create_ipc(event_handler* handler, ipc_type type, const char* param) -{ - if (type == IPC_SHARED_MEM) - { - // path-file:id:size[:write-ratio-> percent of size of sent buffer, default is 50, only valid in owner] - std::string file(param); - size_t pos = file.rfind(':'); - std::vector params; - - while(pos != std::string::npos && params.size() < 3) - { - params.push_back(std::stold(file.substr(pos + 1))); - file.erase(pos); - pos = file.rfind(':'); - } - if(params.size() >= 2) - { - params.insert(params.begin(), 50); - pos = params.size(); - - return dynamic_cast(new ipc_wrapper_shm(file.c_str(), params[pos - 1], params[pos - 2], handler, params[pos - 3])); - } - } - return nullptr; -} diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_wrapper.h b/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_wrapper.h deleted file mode 100644 index 1263de0..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/ipc_wrapper.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -// IPC utility -// -// created on 2022-12-02 -// - - -#include "event_monitor.h" - - -class ipc_wrapper : public parent_holder -{ -protected: - event_handler* handler_; - -public: - ipc_wrapper(event_handler* handler); - - enum ipc_type - { - IPC_FILE = 0, // param: path file - IPC_PIPE, // param: pipe name - IPC_NET, // param: dot-ip:port - IPC_SHARED_MEM, // param: path-file:id:size[:write-ratio-> percent of size of sent buffer, default is 50, only valid in owner] - IPC_USB, // param: vid:pid - IPC_COM, // param: COM1 - }; - static ipc_wrapper* create_ipc(event_handler* handler, ipc_type type, const char* param); - -protected: - virtual ~ipc_wrapper(); - -public: - // Function: write content to peer - // - // Parameters: pack - content pack - // - // bytes - [in] bytes of data in 'pack', [out] - bytes of data has sent - // - // kbuf - whether memory 'pack' is from IPC, i.e. return from method get_kbuf() - // - // timeout - time out, in milliseconds - // - // Return: 0 - success - // ENOTCONN - the commuction is not connected, equal to !is_ok() - // EDEADLOCK - calling from current thread is disallowed - // ETIME - time out - // ECANCELED - user cancelled the operation - virtual int32_t write(const char* pack, size_t *bytes, bool kbuf, unsigned timeout = WAIT_INFINITE) = 0; // DON'T call in event_handler::on_event routine, it will be DEAD-LOCK !!! - virtual bool is_ok(void) = 0; // whether the commuction is ready - virtual bool is_first(void) = 0; // whether the communication established by me - - // Function: obtain IPC internal buffer to reduce ONE memory copy for sent data - // - // Parameter: bytes - [in] desired size; [out] - real size - // - // Return: memory pointer if success, or nullptr. call release_kbuf(ptr) if no longer used - virtual void* get_kbuf(size_t* bytes); - virtual void release_kbuf(void* buf); // release the internal buffer returned by get_kbuf - virtual void clear_kernel_objects(void); // clear all kernel objects the IPC used, used to clear exception - virtual bool cancel_write(void); // cancel current write operation - virtual int32_t stop(void) override; // close the connection -}; diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/json/cJSON.h b/device/gxx-linux/testusb/usb-rk3399/src/common/json/cJSON.h deleted file mode 100644 index 913bc1e..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/json/cJSON.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - Copyright (c) 2009 Dave Gamble - - 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. -*/ - -#ifndef cJSON__h -#define cJSON__h -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* cJSON Types: */ -#define cJSON_False 0 -#define cJSON_True 1 -#define cJSON_NULL 2 -#define cJSON_Number 3 -#define cJSON_String 4 -#define cJSON_Array 5 -#define cJSON_Object 6 - -#define cJSON_IsReference 256 -#define cJSON_StringIsConst 512 - - -typedef void *(*malloc_fnxx)(size_t sz); -typedef void (*free_fnxx)(void *ptr); - -/* The cJSON structure: */ -typedef struct cJSON { - struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ - struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - - int type; /* The type of the item, as above. */ - - char *valuestring; /* The item's string, if type==cJSON_String */ - int valueint; /* The item's number, if type==cJSON_Number */ - double valuedouble; /* The item's number, if type==cJSON_Number */ - - char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ -} cJSON; - -typedef struct cJSON_Hooks { - malloc_fnxx malloc_fn; - free_fnxx free_fn; -} cJSON_Hooks; - -/* Supply malloc, realloc and free functions to cJSON */ -extern void cJSON_InitHooks(cJSON_Hooks* hooks); - - -/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ -extern cJSON *cJSON_Parse(const char *value); -/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ -extern char *cJSON_Print(cJSON *item); -/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ -extern char *cJSON_PrintUnformatted(cJSON *item); -/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); -/* Delete a cJSON entity and all subentities. */ -extern void cJSON_Delete(cJSON *c); - -/* Returns the number of items in an array (or object). */ -extern int cJSON_GetArraySize(cJSON *array); -/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ -extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); -/* Get item "string" from object. Case insensitive. */ -extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); - -/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -extern const char *cJSON_GetErrorPtr(void); - -/* These calls create a cJSON item of the appropriate type. */ -extern cJSON *cJSON_CreateNull(void); -extern cJSON *cJSON_CreateTrue(void); -extern cJSON *cJSON_CreateFalse(void); -extern cJSON *cJSON_CreateBool(int b); -extern cJSON *cJSON_CreateNumber(double num); -extern cJSON *cJSON_CreateString(const char *string); -extern cJSON *cJSON_CreateArray(void); -extern cJSON *cJSON_CreateObject(void); - -/* These utilities create an Array of count items. */ -extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); -extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); -extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); -extern cJSON *cJSON_CreateStringArray(const char **strings,int count); - -/* Append item to the specified array/object. */ -extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); -extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); -extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */ -/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); - -/* Remove/Detatch items from Arrays/Objects. */ -extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); -extern void cJSON_DeleteItemFromArray(cJSON *array,int which); -extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); -extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); - -/* Update array items. */ -extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */ -extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); -extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); - -/* Duplicate a cJSON item */ -extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); -/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will -need to be released. With recurse!=0, it will duplicate any children connected to the item. -The item->next and ->prev pointers are always zero on return from Duplicate. */ - -/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ -extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); - -extern void cJSON_Minify(char *json); - -// convert e681a2 to \u6062, call 'free' to free the returned value -extern char* cJSON_utf8_2_unic(const char* utf8); - -/* Macros for creating things quickly. */ -#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) -#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) -#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) -#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) -#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) -#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) - -/* When assigning an integer value, it needs to be propagated to valuedouble too. */ -#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) -#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/json/json.cpp b/device/gxx-linux/testusb/usb-rk3399/src/common/json/json.cpp deleted file mode 100644 index e8ae93f..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/json/json.cpp +++ /dev/null @@ -1,786 +0,0 @@ - -#include "json.h" -#include "cJSON.h" -#include -#include - -namespace special_char_trans -{ - struct - { - const char* writedown_text; - char readable_char; - }transferred_chars[] = { { "\\\"", '\"' } - , { "\\'", '\'' } - , { "\\a", '\a' } - , { "\\b", '\b' } - , { "\\f", '\f' } - , { "\\n", '\n' } - , { "\\r", '\r' } - , { "\\t", '\t' } - , { "\\v", '\v' } - // , { "\\?", '\?' } - , { "\\\\", '\\' } - , { "\\/", '/' } - // , { "\\0", '\0' } - }; - - void to_writedown(std::string& str) - { - std::string trans(str); - const char* ptr = trans.c_str(); - - str.clear(); - while (*ptr) - { - bool rep = false; - if (*ptr == '\\') - { - if (ptr[1] == '\\') - { - str += "\\\\"; - ptr++; - rep = true; - } - else if( ptr[1] == '/' || - ptr[1] == 'a' || - ptr[1] == 'b' || - ptr[1] == 'f' || - ptr[1] == 'n' || - ptr[1] == 'r' || - ptr[1] == 't' || - ptr[1] == 'u' || - ptr[1] == 'v') - { - str += "\\"; - ptr++; - } - else - { - str += "\\\\"; - rep = true; - } - } - else - { - for (size_t i = 0; i < sizeof(transferred_chars) / sizeof(transferred_chars[0]); ++i) - { - if (*ptr == transferred_chars[i].readable_char) - { - str += transferred_chars[i].writedown_text; - rep = true; - break; - } - } - } - if (!rep) - str.append(1, *ptr); - ptr++; - } - } -} - - -json::json(char* json_txt) : type_(VAL_TYPE_OBJECT), key_(""), strval_(""), cur_child_(-1) -{ - simple_val_.dval = .0f; - if(json_txt) - attach_text(json_txt); -} -json::json(const char* key, bool val) : type_(VAL_TYPE_BOOL), key_(key ? key : ""), strval_(""), cur_child_(-1) -{ - simple_val_.bval = val; -} -json::json(const char* key, int val) : type_(VAL_TYPE_INT), key_(key ? key : ""), strval_(""), cur_child_(-1) -{ - simple_val_.nval = val; -} -json::json(const char* key, double val) : type_(VAL_TYPE_FLOAT), key_(key ? key : ""), strval_(""), cur_child_(-1) -{ - simple_val_.dval = val; -} -json::json(const char* key, const char* val) : type_(VAL_TYPE_STRING), key_(key ? key : ""), strval_(val ? val : ""), cur_child_(-1) -{} -json::~json() -{ - clear(); -} - -std::string json::object_key(json* jsn) -{ - return "\"" + jsn->key() + "\":"; -} -std::string json::array_key(json* jsn) -{ - return ""; -} - -void json::from_cjson(cJSON* cj) -{ - key_ = cj && cj->string ? cj->string : ""; - while (cj) - { - json* child = nullptr; - if (cj->type == cJSON_True) - { - child = new json(cj->string, true); - } - else if(cj->type == cJSON_False) - { - child = new json(cj->string, false); - } - else if (cj->type == cJSON_Number) - { - if (cj->valuedouble - (int)cj->valuedouble < .00001) - { - child = new json(cj->string, cj->valueint); - } - else - { - child = new json(cj->string, cj->valuedouble); - } - } - else if (cj->type == cJSON_String) - { - child = new json(cj->string, cj->valuestring); - } - else if (cj->type == cJSON_Object || cj->type == cJSON_Array) - { - child = new json(); - child->from_cjson(cj->child); - child->key_ = cj->string ? cj->string : ""; - } - arr_val_.push_back(child); - cj = cj->next; - } - - if (arr_val_.size() == 1 && arr_val_[0]->arr_val_.size() == 0) - { - json* child = arr_val_[0]; - - if (!child->key_.empty()) // array - { - arr_val_.clear(); - type_ = child->type_; - key_ = child->key_; - simple_val_.dval = child->simple_val_.dval; - strval_ = child->strval_; - for (auto& v : child->arr_val_) - arr_val_.push_back(v); - child->arr_val_.clear(); - child->release(); - } - } - - if (arr_val_.size()) - { - type_ = arr_val_[0]->key().empty() ? VAL_TYPE_ARRAY : VAL_TYPE_OBJECT; - } -} -json* json::find_child(const char* key, bool remove) -{ - json* ret = nullptr; - - if (type_ == VAL_TYPE_OBJECT) - { - for (size_t i = 0; i < arr_val_.size(); ++i) - { - if (arr_val_[i]->key() == key) - { - ret = arr_val_[i]; - if (remove) - arr_val_.erase(arr_val_.begin() + i); - else - ret->add_ref(); - - break; - } - } - } - - return ret; -} - -bool json::attach_text(char* json_txt) -{ - clear(); - - cJSON* jsn = cJSON_Parse(json_txt); - if (jsn) - { - char *text = cJSON_Print(jsn); - if (text) - free(text); - - from_cjson(jsn->child); - cJSON_Delete(jsn); - - return true; - } - - return false; -} -void json::clear(bool as_array) -{ - if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) - { - for (auto& v : arr_val_) - v->release(); - } - type_ = as_array ? VAL_TYPE_ARRAY : VAL_TYPE_OBJECT; - simple_val_.dval = .0f; - key_ = ""; - strval_ = ""; - arr_val_.clear(); - cur_child_ = -1; -} -std::string json::to_string(void) -{ - if (type_ == VAL_TYPE_NULL) - return ""; - if (type_ == VAL_TYPE_BOOL) - return (simple_val_.bval ? "true" : "false"); - if (type_ == VAL_TYPE_INT) - return std::to_string(simple_val_.nval); - if (type_ == VAL_TYPE_FLOAT) - return std::to_string(simple_val_.dval); - if (type_ == VAL_TYPE_STRING) - { - char* u = cJSON_utf8_2_unic(strval_.c_str()); - std::string r(u); - - free(u); - special_char_trans::to_writedown(r); - - return "\"" + r + "\""; - } - - std::string(*k)(json*) = type_ == VAL_TYPE_OBJECT ? json::object_key : json::array_key; - std::string str(type_ == VAL_TYPE_OBJECT ? "{" : "["); - - if (arr_val_.size()) - { - str += k(arr_val_[0]) + arr_val_[0]->to_string(); - for(size_t i = 1; i < arr_val_.size(); ++i) - str += "," + k(arr_val_[i]) + arr_val_[i]->to_string(); - } - str += type_ == VAL_TYPE_OBJECT ? "}" : "]"; - - return str; -} - -std::string& json::key(void) -{ - return key_; -} -bool json::is_array(void) -{ - return type_ == VAL_TYPE_ARRAY; -} -bool json::is_leaf_node(void) -{ - return type_ == VAL_TYPE_BOOL || - type_ == VAL_TYPE_INT || - type_ == VAL_TYPE_FLOAT || - type_ == VAL_TYPE_STRING; -} - -bool json::get_value(const char* key, bool& val) -{ - bool ret = false; - json* child = find_child(key); - - if (child) - { - if (child->type_ == VAL_TYPE_BOOL) - { - val = child->simple_val_.bval; - ret = true; - } - child->release(); - } - else if (type_ == VAL_TYPE_BOOL && key_ == key) - { - val = simple_val_.bval; - ret = true; - } - - return ret; -} -bool json::get_value(const char* key, int& val) -{ - bool ret = false; - json* child = find_child(key); - - if (child) - { - if (child->type_ == VAL_TYPE_INT) - { - val = child->simple_val_.nval; - ret = true; - } - child->release(); - } - else if (type_ == VAL_TYPE_INT && key_ == key) - { - val = simple_val_.nval; - ret = true; - } - - return ret; -} -bool json::get_value(const char* key, double& val) -{ - bool ret = false; - json* child = find_child(key); - - if (child) - { - if (child->type_ == VAL_TYPE_FLOAT) - { - val = child->simple_val_.dval; - ret = true; - } - child->release(); - } - else if (type_ == VAL_TYPE_FLOAT && key_ == key) - { - val = simple_val_.dval; - ret = true; - } - - return ret; -} -bool json::get_value(const char* key, std::string& val) -{ - bool ret = false; - json* child = find_child(key); - - if (child) - { - if (child->type_ == VAL_TYPE_STRING) - { - val = child->strval_; - ret = true; - } - child->release(); - } - else if (type_ == VAL_TYPE_STRING && key_ == key) - { - val = strval_; - ret = true; - } - - return ret; -} -bool json::get_value(const char* key, json*& val) -{ - bool ret = false; - json *child = find_child(key); - - if (child) - { - if (child->type_ == VAL_TYPE_OBJECT) - { - val = child; - ret = true; - } - else - { - child->release(); - } - } - - return ret; -} - -size_t json::children(void) -{ - if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) - return arr_val_.size(); - else - return -1; -} -json* json::child(size_t ind) -{ - if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) - { - if (ind >= 0 && ind < arr_val_.size()) - { - arr_val_[ind]->add_ref(); - - return arr_val_[ind]; - } - } - - return nullptr; -} -json* json::first_child(void) -{ - if (type_ == VAL_TYPE_OBJECT || type_ == VAL_TYPE_ARRAY) - { - cur_child_ = 0; - if (arr_val_.size()) - { - arr_val_[0]->add_ref(); - - return arr_val_[0]; - } - } - - return nullptr; -} -json* json::next_child(void) -{ - if (type_ == VAL_TYPE_OBJECT || type_ == VAL_TYPE_ARRAY) - { - if (++cur_child_ < arr_val_.size()) - { - arr_val_[cur_child_]->add_ref(); - - return arr_val_[cur_child_]; - } - } - - return nullptr; -} - -bool json::set_value(const char* key, bool val) -{ - if (type_ != VAL_TYPE_OBJECT) - return false; - - json* child = find_child(key); - - if (child) - { - child->clear(); - child->type_ = VAL_TYPE_BOOL; - child->key() = key ? key : ""; - child->simple_val_.bval = val; - child->release(); - } - else - { - child = new json(key, val); - arr_val_.push_back(child); - } - - return true; -} -bool json::set_value(const char* key, int val) -{ - if (type_ != VAL_TYPE_OBJECT) - return false; - - json* child = find_child(key); - - if (child) - { - child->clear(); - child->type_ = VAL_TYPE_INT; - child->key() = key ? key : ""; - child->simple_val_.nval = val; - child->release(); - } - else - { - child = new json(key, val); - arr_val_.push_back(child); - } - - return true; -} -bool json::set_value(const char* key, double val) -{ - if (type_ != VAL_TYPE_OBJECT) - return false; - - json* child = find_child(key); - - if (child) - { - child->clear(); - child->type_ = VAL_TYPE_FLOAT; - child->key() = key ? key : ""; - child->simple_val_.dval = val; - child->release(); - } - else - { - child = new json(key, val); - arr_val_.push_back(child); - } - - return true; -} -bool json::set_value(const char* key, const char* val) -{ - if (type_ != VAL_TYPE_OBJECT) - return false; - - json* child = find_child(key); - - if (child) - { - child->clear(); - child->type_ = VAL_TYPE_STRING; - child->key() = key ? key : ""; - child->strval_ = val ? val : ""; - child->release(); - } - else - { - child = new json(key, val); - arr_val_.push_back(child); - } - - return true; -} -bool json::set_value(const char* key, json* val) -{ - if (type_ != VAL_TYPE_OBJECT) - return false; - - for (size_t i = 0; i < arr_val_.size(); ++i) - { - if (arr_val_[i]->key() == key) - { - arr_val_[i]->release(); - arr_val_[i] = val; - val->add_ref(); - return true; - } - } - - arr_val_.push_back(val); - val->key() = key; - val->add_ref(); - - return true; -} - -json& json::operator+=(bool val) -{ - if (type_ == VAL_TYPE_ARRAY) - { - json* child = new json(nullptr, val); - arr_val_.push_back(child); - } - - return *this; -} -json& json::operator+=(int val) -{ - if (type_ == VAL_TYPE_ARRAY) - { - json* child = new json(nullptr, val); - arr_val_.push_back(child); - } - - return *this; -} -json& json::operator+=(double val) -{ - if (type_ == VAL_TYPE_ARRAY) - { - json* child = new json(nullptr, val); - arr_val_.push_back(child); - } - - return *this; -} -json& json::operator+=(const char* val) -{ - if (type_ == VAL_TYPE_ARRAY) - { - json* child = new json(nullptr, val); - arr_val_.push_back(child); - } - - return *this; -} -json& json::operator+=(json* val) -{ - if (type_ == VAL_TYPE_ARRAY) - { - val->add_ref(); - arr_val_.push_back(val); - } - - return *this; -} - -json& json::operator-=(int ind) -{ - remove(ind); - - return *this; -} -bool json::remove(const char* key) -{ - json* child = find_child(key, true); - - if (child) - { - child->release(); - return true; - } - else - { - return false; - } -} -bool json::remove(json* child) -{ - if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) - { - for (size_t i = 0; i < arr_val_.size(); ++i) - { - if (arr_val_[i] == child) - { - arr_val_[i]->release(); - arr_val_.erase(arr_val_.begin() + i); - - return true; - } - } - } - - return false; -} -bool json::remove(int ind) -{ - bool ret = false; - - if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) - { - if (ind >= 0 && ind < arr_val_.size()) - { - arr_val_[ind]->release(); - arr_val_.erase(arr_val_.begin() + ind); - ret = true; - } - } - - return ret; -} - -int json::index(json* child) -{ - if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) - { - for (int i = 0; i < arr_val_.size(); ++i) - { - if (arr_val_[i] == child) - return i; - } - } - - return -1; -} -int json::index_move_to(json* child, int ind) -{ - int i = index(child); - - if (i == -1) - return -1; - - arr_val_.erase(arr_val_.begin() + i); - if (ind < 0) - ind = 0; - if (ind > arr_val_.size()) - ind = arr_val_.size(); - arr_val_.insert(arr_val_.begin() + ind, child); - - return ind; -} - -bool json::value(bool& val) -{ - bool ret = false; - - if (is_leaf_node() && type_ == VAL_TYPE_BOOL) - { - val = simple_val_.bval; - ret = true; - } - - return ret; -} -bool json::value(int& val) -{ - bool ret = false; - - if (is_leaf_node() && type_ == VAL_TYPE_INT) - { - val = simple_val_.nval; - ret = true; - } - - return ret; -} -bool json::value(double& val) -{ - bool ret = false; - - if (is_leaf_node() && type_ == VAL_TYPE_FLOAT) - { - val = simple_val_.dval; - ret = true; - } - - return ret; -} -bool json::value(std::string& val) -{ - bool ret = false; - - if (is_leaf_node() && type_ == VAL_TYPE_STRING) - { - val = strval_; - ret = true; - } - - return ret; -} -json& json::operator=(bool val) -{ - if (is_leaf_node()) - { - simple_val_.bval = val; - type_ = VAL_TYPE_BOOL; - } - - return *this; -} -json& json::operator=(int val) -{ - if (is_leaf_node()) - { - simple_val_.nval = val; - type_ = VAL_TYPE_INT; - } - - return *this; -} -json& json::operator=(double val) -{ - if (is_leaf_node()) - { - simple_val_.dval = val; - type_ = VAL_TYPE_FLOAT; - } - - return *this; -} -json& json::operator=(const char* val) -{ - if (is_leaf_node()) - { - strval_ = val ? val : ""; - type_ = VAL_TYPE_STRING; - } - - return *this; -} diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/json/json.h b/device/gxx-linux/testusb/usb-rk3399/src/common/json/json.h deleted file mode 100644 index 3adff81..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/json/json.h +++ /dev/null @@ -1,148 +0,0 @@ -#pragma once - -#ifdef TEST_JSON -#include -class refer -{ - volatile int32_t ref_; - std::mutex mutex_; - -protected: - refer() : ref_(1) - {} - virtual ~refer() - {} - - virtual void on_born(void) {} - virtual void on_dead(void) {} - -public: - virtual int32_t add_ref(void) - { - std::lock_guard l(mutex_); - - return ++ref_; - } - virtual int32_t release(void) - { - int32_t ref; - - { - std::lock_guard l(mutex_); - ref = --ref_; - } - - if (ref == 0) - { - delete this; - } - - return ref; - } -}; -#else -#include "../referer.h" -#endif -#include -#include - -struct cJSON; - -class json : public refer -{ - enum val_type - { - VAL_TYPE_NULL = 0, - VAL_TYPE_BOOL, - VAL_TYPE_INT, - VAL_TYPE_FLOAT, - VAL_TYPE_STRING, - VAL_TYPE_OBJECT, - VAL_TYPE_ARRAY, - }; - val_type type_; - std::string key_; - union - { - bool bval; - int nval; - double dval; - }simple_val_; - std::string strval_; - std::vector arr_val_; - size_t cur_child_; - - static std::string object_key(json* jsn); - static std::string array_key(json* jsn); - - void from_cjson(cJSON* cj); - json* find_child(const char* key, bool remove = false); - -public: - json(char* json_txt = 0); - -protected: - json(const char* key, bool val); - json(const char* key, int val); - json(const char* key, double val); - json(const char* key, const char* val); - ~json(); - -public: - // parse/un-parse ... - bool attach_text(char* json_txt); - void clear(bool as_array = false); - std::string to_string(void); - - // attributes ... - std::string& key(void); - bool is_array(void); - bool is_leaf_node(void); // whether this object is a leaf node contains final value - - // value access ... - bool get_value(const char* key, bool& val); - bool get_value(const char* key, int& val); - bool get_value(const char* key, double& val); - bool get_value(const char* key, std::string& val); - bool get_value(const char* key, json*& val); - - // enumeration ... - size_t children(void); // return children count if was object or array, or else -1 returned - json* child(size_t ind); - json* first_child(void); - json* next_child(void); - - // change the item matching 'key', otherwise add a new item - bool set_value(const char* key, bool val); - bool set_value(const char* key, int val); - bool set_value(const char* key, double val); - bool set_value(const char* key, const char* val); - bool set_value(const char* key, json* val); - - // operator+= only for array - json& operator+=(bool val); - json& operator+=(int val); - json& operator+=(double val); - json& operator+=(const char* val); - json& operator+=(json* val); - - // remove item - json& operator-=(int ind); - bool remove(const char* key); - bool remove(json* child); - bool remove(int ind); - - // position management - int index(json* child); - int index_move_to(json* child, int ind); - - // leaf node value ... - bool value(bool& val); - bool value(int& val); - bool value(double& val); - bool value(std::string& val); - json& operator=(bool val); - json& operator=(int val); - json& operator=(double val); - json& operator=(const char* val); -}; diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/log_util.cpp b/device/gxx-linux/testusb/usb-rk3399/src/common/log_util.cpp deleted file mode 100644 index a90f48f..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/log_util.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include "log_util.h" - -#include -#include -#include - -#if !defined(WIN32) && !defined(_WIN64) -#include -#include -#include -#include "sys_util.h" - -#else -#include -#include - - -namespace sys_util -{ - static std::string get_module_path(const char* name = NULL) - { - char path[MAX_PATH] = { 0 }; - - GetModuleFileNameA(NULL, path, _countof(path) - 1); - - return path; - } -} -#endif - -#include "referer.h" - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// class�� -log_cls* log_cls::inst_ = nullptr; - -log_cls::log_cls(const char* path_file, log_level level, int32_t max_size) : file_(path_file), max_size_(max_size), level_(level), dst_(nullptr) -{ - create_log_file(); -} -log_cls::~log_cls() -{ - if (dst_) - fclose(dst_); -} - -void log_cls::create_log_file(void) -{ - dst_ = fopen(file_.c_str(), "a+b"); - if (dst_) - { - fseek(dst_, 0, SEEK_END); - if (ftell(dst_) == 0) - { - unsigned char bom[] = { 0x0ef, 0x0bb, 0x0bf }; - fwrite(bom, sizeof(bom), 1, dst_); - } - else - fwrite("\n\n\n", 1, 3, dst_); - } - else - printf("# Failed to create log file(%s): %d(%s)\n", file_.c_str(), errno, strerror(errno)); -} - -void log_cls::log_internal(const char* txt) -{ - std::string now("[" + chronograph::now() + "] "); - - now += txt; - { - LOCKER locker(lock_); - if (dst_) - { - size_t wrote = fwrite(now.c_str(), 1, now.length(), dst_); - if(wrote != now.length()) - printf("# Write log failed: %d(%s)\n", errno, strerror(errno)); - - fflush(dst_); - if (ftell(dst_) >= max_size_) - { - fclose(dst_); - remove(file_.c_str()); - create_log_file(); - } - } - } -} - -void log_cls::initialize(const char* path_file, log_level level, int32_t max_size) -{ - if (log_cls::inst_) - delete log_cls::inst_; - - std::string path(""); - - if (!path_file || *path_file == 0) - { - size_t pos = 0; - std::string def_dir(std::string(getenv(USER_DIR)) + PATH_SEPARATOR + ".scanner"); // +PATH_SEPARATOR + "log"); - -#if defined(WIN32) || defined(_WIN64) - mkdir(def_dir.c_str()); -#endif - - def_dir += std::string(PATH_SEPARATOR) + "log"; - path = sys_util::get_module_path(); - pos = path.rfind(PATH_SEPARATOR[0]); - if (pos++ != std::string::npos) - path.erase(0, pos); - path.insert(0, def_dir + PATH_SEPARATOR); -#if defined(WIN32) || defined(_WIN64) - mkdir(def_dir.c_str()); -#else - sys_util::create_folder(def_dir.c_str()); -#endif - path += ".log"; - path_file = path.c_str(); - } - log_cls::inst_ = new log_cls(path_file, level, max_size); -} -int32_t log_cls::log_when_err(int32_t err, const char* oper_desc, log_level level) -{ - if(err == -1) - { - err = errno; - log_cls::log(level, "%s = %s\n", oper_desc, strerror(err)); - } - - return err; -} -log_level log_cls::get_log_level(void) -{ - if (log_cls::inst_) - return log_cls::inst_->level_; - else - return LOG_LEVEL_ALL; -} -std::string log_cls::get_log_file(void) -{ - if (log_cls::inst_) - return log_cls::inst_->file_; - else - return ""; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/log_util.h b/device/gxx-linux/testusb/usb-rk3399/src/common/log_util.h deleted file mode 100644 index 3778ba0..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/log_util.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -// log utility -// -// created on 2022-11-30 -// - - -#include "referer.h" -#include -#include - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// object event -// -enum log_level -{ - LOG_LEVEL_ALL = 0, - LOG_LEVEL_DEBUG, - LOG_LEVEL_WARNING, - LOG_LEVEL_FATAL, -}; - -class log_cls -{ - std::string file_; - int32_t max_size_; - log_level level_; - MUTEX lock_; - FILE *dst_; - - static log_cls* inst_; - - void create_log_file(void); - -protected: - log_cls(const char* path_file, log_level level, int32_t max_size); - ~log_cls(); - - void log_internal(const char* txt); - -public: - static void initialize(const char* path_file, log_level level = LOG_LEVEL_ALL, int32_t max_size = SIZE_MB(10)); - - template - static void log(log_level level, const char* fmt, Args ... args) - { - if (level >= log_cls::get_log_level() && log_cls::inst_) - { - size_t size = snprintf(nullptr, 0, fmt, args ...) + 1; - std::unique_ptr buf(new char[size]); - - snprintf(buf.get(), size, fmt, args ...); - - log_cls::inst_->log_internal(buf.get()); - } - } - static int32_t log_when_err(int32_t err, const char* oper_desc, log_level level = LOG_LEVEL_WARNING); // log as: oper_desc = strerror(errno)\n. return real error number errno - - static log_level get_log_level(void); - static std::string get_log_file(void); -}; diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/packet.h b/device/gxx-linux/testusb/usb-rk3399/src/common/packet.h deleted file mode 100644 index 4f14a56..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/packet.h +++ /dev/null @@ -1,315 +0,0 @@ -#pragma once - -// packet structures and command -// -// created on 2022-12-06 -// -#if !defined(WIN32) -#include -#endif -#include - -/////////////////////////////////////////////////////////////////////////////// -// definitions ... -#define CONFIG_NAME_MAX_LEN 32 // max bytes of configuration name -#define MAKE_WORD(b0, b1) (((b0) & 0xff) | (((b1) << 8) & 0x0ff00)) -#define ROGER(cmd) cmd##_ROGER -#define PAIR_COMMAND(cmd) \ - cmd, \ - cmd##_ROGER - -#define STRUCT_CONSTRUCTOR(st_name) \ - st_name() \ - { \ - memset(this, 0, sizeof(st_name));\ - } - -// protocol version, The first thing to do after connecting is to check whether the field is compatible !!! -#define PROTOCOL_VER MAKE_WORD(0, 1) - -// NOTE: All text transmitted by pack cmd is in UTF-8 format !!! - - -enum ep0_req -{ - USB_REQ_EP0_GET_PROTO_VER = 100, // get protocol version (PROTOCOL_VER), req = me, ind = 0, val = 0, len = 2 - USB_REQ_EP0_GET_STATUS, // 获取各工作线程状态, return EP0REPLYSTATUS. req = me, ind = 0, val = 0, len = sizeof(EP0REPLYSTATUS) - USB_REQ_EP0_RESET_BULK, // 关闭并重新打开BULK端点, return error number (uint32_t). req = me, ind = 0, val = 0, len = sizeof(uint32_t) - USB_REQ_EP0_CANCEL_CMD, // 取消当前指令的继续执行(一般用于中止大数据的传输). req = me, ind = 0, val = 0, len = sizeof(uint32_t) * 2 [(uint32_t)cmd + (uint32_t)pack-id] -}; -enum bulk_status -{ - BULK_STATUS_NOT_START = 0, // has not initialized - BULK_STATUS_IDLE, // wait IO - BULK_STATUS_IO, // in reading or writing - BULK_STATUS_ERROR, // error occurs - BULK_STATUS_RESET, // in reset(close and reopen) process -}; - -enum packet_cmd -{ - PACK_CMD_NULL, - - PAIR_COMMAND(PACK_CMD_HEART_BEAT), // notify peers you are still alive, receiver should reply the same pack - PAIR_COMMAND(PACK_CMD_INVALID), // reply when received an invalid packet - PAIR_COMMAND(PACK_CMD_SYNC), - - // attributes get/set, all content in PACK_BASE::payload should be in JSON style - all readonly attributes move to readonly SANE-options on 2023-03-20 - //PACK_CMD_ATTR_SYS_VER_GET = 10, // get system version on device, [in]: PACK_BASE, [out] PACK_BASE::payload - {"os":"linux", "ver":"4.4.194", ...} - //PACK_CMD_ATTR_FIRMWARE_VER_GET, // get firmware version, [in]: PACK_BASE, [out] PACK_BASE::payload - {"firmware":"G2393A1234", "CIS":"CIS-123", ...} - //PACK_CMD_ATTR_SERIAL_NUM_GET, // get device serial num, [in]: PACK_BASE, [out] PACK_BASE::payload - {"serial":"20221206001"} - //PACK_CMD_ATTR_SERIAL_NUM_SET, // set device serial num, [in]: PACK_BASE::payload - {"serial":"20221206001"}, [out] PACK_BASE - //PACK_CMD_ATTR_MAC_GET, // get mac address, [in]: PACK_BASE, [out] PACK_BASE::payload - {"mac":"12:34:56:78:9a:bc"} - //PACK_CMD_ATTR_IP_GET, // get ip address, [in]: PACK_BASE, [out] PACK_BASE::payload - {"ipv4":"192.168.1.123", "ipv6":"::1"} - //PACK_CMD_ATTR_HARDWARE_INFO_GET, // get hardwares information on device, [in]: PACK_BASE, [out] PACK_BASE::payload - {"CPU":"ARM x86", "mem":"16GB", ...} - //PACK_CMD_ATTR_HISTORY_COUNT_GET, // get history count, [in]: PACK_BASE, [out] PACK_BASE::payload - {"history-count":12345, ...} - //PACK_CMD_ATTR_ROLLER_COUNT_GET, // get roller count, [in]: PACK_BASE, [out] PACK_BASE::payload - {"roller-count":2345} - //PACK_CMD_ATTR_ROLLER_COUNT_SET, // set roller count, [in]: PACK_BASE::payload - {"roller-count":2345}, [out] PACK_BASE - - // configuration get/set - PACK_CMD_STATUS_ROGER = 100, // device -> host. PACK_BASE::result -> status - PAIR_COMMAND(PACK_CMD_SETTING_GET), // get all settings supported by the device, [in]: PACK_BASE, [out]: PACK_BASE::payload - configuration JSON, see SANE-configuration format - PAIR_COMMAND(PACK_CMD_SETTING_GET_CUR), // get current value of given setting, [in]: PACK_BASE::payload - (char*)name, [out]: PACK_BASE::payload - LPCFGVAL - PAIR_COMMAND(PACK_CMD_SETTING_SET), // set value of given setting, [in]: PACK_BASE::payload - LPCFGVAL, [out]: PACK_BASE::payload - LPCFGVAL - PAIR_COMMAND(PACK_CMD_SETTING_RESTORE), // restore given settings, [in]: PACK_BASE::payload - LPCFGVAL, [out]: PACK_BASE::payload - LPCFGVAL - - // scan command - PACK_CMD_SCAN_BASE = 200, - PAIR_COMMAND(PACK_CMD_SCAN_START), // start scanning, [in]: PACK_BASE, [out]: PACK_BASE - PAIR_COMMAND(PACK_CMD_SCAN_IMG), // device -> host, PACK_BASE::payload - LPPACKIMAGE - PACK_CMD_SCAN_FINISHED_ROGER, // device -> host, PACK_BASE - PAIR_COMMAND(PACK_CMD_SCAN_STOP), // stop scanning, [in]: PACK_BASE, [out]: PACK_BASE - //PAIR_COMMAND(PACK_CMD_SCAN_IMAGE_REQ), // get image request, [in]: PACK_BASE, [out] PACK_BASE on error, or PACK_BASE::payload - LPPACKIMAGE - //PAIR_COMMAND(PACK_CMD_SCAN_STATUS), // get scanner status, [in]: PACK_BASE, [out] PACK_BASE::result is status code - - // file operation - PACK_CMD_FILE_BASE = 300, - //PAIR_COMMAND(PACK_CMD_FILE_QUERY), // query file information, [in]: PACK_BASE::payload - (char*)file-path, [out] PACK_BASE::payload - LPFILEINFO - PAIR_COMMAND(PACK_CMD_FILE_READ_REQ), // read file content, [in]: PACK_BASE::payload - LPTXFILE, [out] PACK_BASE::payload - LPTXFILE - PAIR_COMMAND(PACK_CMD_FILE_WRITE_REQ), // write a file, [in]: PACK_BASE::payload - LPTXFILE, [out] PACK_BASE - PAIR_COMMAND(PACK_CMD_FILE_MOVE), // move/rename a file, [in]: PACK_BASE::payload - src\0dst\0\0, [out] PACK_BASE - PAIR_COMMAND(PACK_CMD_FILE_REMOVE), // delete a file, [in]: PACK_BASE::payload - (char*)file-path, [out] PACK_BASE - - // process operation - PACK_CMD_PROCESS_BASE = 400, - PAIR_COMMAND(PACK_CMD_PROCESS_START), // start a program [in]: PACK_BASE::payload - (char*)pe\0param\0\0, [out]: PACK_BASE::payload - (uint64_t)process-id on success or PACK_BASE on failure - PAIR_COMMAND(PACK_CMD_PROCESS_STOP), // kill a process [in]: PACK_BASE::payload - (char*)process-id, [out]: PACK_BASE - PAIR_COMMAND(PACK_CMD_PROCESS_REBOOT), // reboot system, [in]: PACK_BASE, [out]: PACK_BASE - //PAIR_COMMAND(PACK_CMD_PROCESS_EXEC_RESULT), // get result of a command, [in]: PACK_BASE::payload - (char*)command string, [out]: PACK_BASE::payload - (char*)execute result. popen(), fgets ... - //PAIR_COMMAND(PACK_CMD_PROCESS_QUERY), // query process information [in]: PACK_BASE::payload - (char*)process-id(-1 for all), [out]: LPPROCINFO - - PACK_CMD_TOKEN_GET = 900, // Obtain the token of the required command, [in] PACK_BASE, [out] - PACK_BASE::payload - LPOPERTOKEN -}; - -enum scanner_status -{ - SCANNER_STATUS_READY = 0, - SCANNER_STATUS_NOT_OPEN, - SCANNER_STATUS_LOST_CONNECT, - SCANNER_STATUS_RESET_BULK, - SCANNER_STATUS_START_SCANNING, // start ok, but scanning-thread not working - SCANNER_STATUS_SCANNING, // start ok, and scanning-thread is working - SCANNER_STATUS_SCAN_FINISHED, // not a persistance status - SCANNER_STATUS_BUSY, // doing task exclude scanning - SCANNER_STATUS_COVER_OPENNED, - SCANNER_STATUS_SLEEPING, - SCANNER_STATUS_COUNT_MODE, - SCANNER_STATUS_DOUBLE_FEEDED, - SCANNER_STATUS_PAPER_JAMMED, - SCANNER_STATUS_PAPER_ASKEW, - SCANNER_STATUS_FEED_FAILED, - SCANNER_STATUS_NO_PAPER, - SCANNER_STATUS_CFG_CHANGED, // PACK_BASE::payload - LPCFGVAL -}; - -enum img_format -{ - IMG_FMT_UNKNOWN = 0, // unknown format - IMG_FMT_TIFF, - IMG_FMT_BMP, - IMG_FMT_JPEG, - IMG_FMT_PNG, - IMG_FMT_SVG, - IMG_FMT_WEBP, - IMG_FMT_GIF, -}; -enum img_compression -{ - IMG_COMPRESSION_NONE = 0, - IMG_COMPRESSION_GROUP4, - IMG_COMPRESSION_RLE4, - IMG_COMPRESSION_RLE8, - IMG_COMPRESSION_LZW, - IMG_COMPRESSION_ZIP, -}; -enum img_status -{ - IMG_STATUS_OK = 0, - IMG_STATUS_DOUBLE, - IMG_STATUS_JAM, - IMG_STATUS_STAPLE, // staples on the paper - IMG_STATUS_SIZE_ERR, // size check failed - IMG_STATUS_DOGEAR, // paper has dogear -}; -enum data_type -{ - DATA_TYPE_BOOL = 0, // (bool*) - DATA_TYPE_INT1, // (uint8_t*) - DATA_TYPE_INT2, // (uint16_t*) - DATA_TYPE_INT4, // (uint32_t*) - DATA_TYPE_INT8, // (uint64_t*) - DATA_TYPE_FLOAT, // (double*) - DATA_TYPE_STRING, // (char*) with max_len space - DATA_TYPE_CUSTOM, -}; - -enum paper_side -{ - PAPER_SIDE_FRONT = 0, // single side, this is front - PAPER_SIDE_BACK, // single side, this is back - PAPER_SIDE_TOP, // VERT-compound sides, and front side is at top - PAPER_SIDE_BOTTOM, // VERT-compound sides, and front side is at bottom - PAPER_SIDE_LEFT, // HORZ-compound sides, and front side is at left - PAPER_SIDE_RIGHT, // HORZ-compound sides, and front side is at right -}; -enum rot_angle -{ - ROT_ANGLE_0 = 0, - ROT_ANGLE_90, - ROT_ANGLE_180, - ROT_ANGLE_270, -}; - -#pragma pack(push) -#pragma pack(1) -typedef struct _ep0_reply -{ - uint8_t in_status; // BULK-IN status, enum bulk_statu - uint8_t out_status; // BULK-OUT status, enum bulk_statu - uint16_t in_err; // valid if in_statu == BULK_STATU_ERROR - uint16_t out_err; // valid if out_statu == BULK_STATU_ERROR - uint16_t task_cnt; // tasks in command queue - uint32_t task_cmd; // the cmd of the task thread is doing - uint32_t task_pack_id; // packet id of the cmd - uint32_t task_required_bytes; // required byte of this packet - uint32_t packets_to_sent; // how many packets in sent queue - uint32_t bytes_to_sent; // how many bytes data is waiting for be sent in one replying packet -}EP0REPLYSTATUS, *LPEP0REPLYSTATUS; - -typedef struct _pack_base // A piece of data has only one header -{ - uint32_t size : 16; // bytes of this structure - uint32_t result : 16; // error code in reply packet, be ZERO in command packet - uint32_t cmd; // packet command - uint32_t pack_id; // maintain by the initiator, the reply use the same id - uint32_t payload_len; // total bytes of payload of this packet (the data in the range will sent in ONE 'write') - char payload[0]; // payloads, according to 'cmd' - - STRUCT_CONSTRUCTOR(_pack_base) -}PACK_BASE, * LPPACK_BASE; -#define BASE_PACKET_REPLY(reply, command, id, err) \ - (reply).size = sizeof(reply); \ - (reply).result = err; \ - (reply).cmd = command; \ - (reply).pack_id = id; \ - (reply).payload_len = 0; - - -typedef struct _config_val -{ - uint8_t type; // same as SANE_Value_Type - uint8_t name_off; // name offset of the option in data, end with '\0' - uint8_t val_off; // option value offset in data - uint8_t after_do; // see SANE_INFO_xxx in sane.h - uint16_t val_size; // real size of value - uint32_t err; // set result - char data[0]; // contains value and name. fetch them according name_off and val_off members. -}CFGVAL, *LPCFGVAL; - -typedef struct _img_pos -{ - uint64_t paper_ind : 32; // paper index in this turn/start, based ZERO. (image-collector set) - uint64_t new_img : 1; // 0 - partial data; 1 - new image data. (image-collector set) - uint64_t img_over : 1; // 0 - has data yet; 1 - END for the image. (image-collector set) - uint64_t paper_side : 3; // enum paper_side. front of paper(When scanning multiple sheets, the paper feeding side is the front side). (image-collector set) - uint64_t back_rot : 2; // back rotation angle, enum rot_angle. (image-collector set) - uint64_t channel_ind : 4; // index of color channel, based ZERO, 0x0f for all channels. (image-collector set) - uint64_t status : 4; // img_status. (image-collector set) - uint64_t split_ind : 7; // splitting order, from left to right and then top to bottom, based ZERO - uint64_t multiout_ind : 4; // index of multi-out - uint64_t reserved : 6; // reserved - - STRUCT_CONSTRUCTOR(_img_pos) -}IMGPOS, * LPIMGPOS; -typedef struct _pack_img -{ - IMGPOS pos; // image pos info ... - uint32_t width; // image width in pixel. (image-collector set) - uint32_t height; // image height in pixel. (image-collector set) - uint32_t resolution_x; // image horizontal reolution. (image-collector set) - uint32_t resolution_y; // image vertical reolution. (image-collector set) - uint32_t channels : 6; // image channels per pixel. (image-collector set) - uint32_t format : 6; // image format, see 'img_format'. (image-collector set) - uint32_t bpp : 6; // bits per pixel. (image-collector set) - uint32_t bppc : 6; // bits per pixel in this channel, equal to 'bpp' if pos.channel_ind == 0x0f. (image-collector set) - uint32_t compression : 6; // image data compression, see 'img_compression'. (image-collector set) - uint32_t reserve : 2; // unused now - uint32_t info_size; // image information size in bytes, information part is used for quality of JPEG, pallete of BMP .... (image-collector set) - uint64_t data_size; // image data size in 'data' with bytes. (image-collector set) - char data[0]; // two parts: image info (info_size) + image data (data_size) - - STRUCT_CONSTRUCTOR(_pack_img) -}PACKIMAGE, * LPPACKIMAGE; - -typedef struct _oper_token -{ - uint32_t type; // token type - char data[128]; // token data -}OPERTOKEN, * LPOPERTOKEN; - -typedef struct _tx_file -{ - uint64_t size; // total size - uint64_t offset; // offset in the file - char path[2]; // file full path-name -}TXFILE, *LPTXFILE; -typedef struct _file_info -{ - OPERTOKEN token; // operation token, returned by command PACK_CMD_TOKEN_GET - uint64_t size; // file size - uint16_t name_len; // bytes of file name string - uint16_t create_time_len; // bytes of create time string: '2022-12-07 12:34:56.789', or target file path in command PACK_CMD_FILE_MOVE - uint16_t modify_time_len; - uint16_t version_len; // bytes of version string - char data[0]; // 4 parts: path-file(name_len) + create-time(create_time_len) + modify-time(modify_time_len) + version(version_len) - // or 5 parts in command PACK_CMD_FILE_WRITE, add content at the last part of bytes 'size' - - STRUCT_CONSTRUCTOR(_file_info) -}FILEINFO, * LPFILEINFO; - -typedef struct _proc_info -{ - OPERTOKEN token; // operation token, returned by command PACK_CMD_TOKEN_GET - uint32_t count; // number of elements in array proc - struct _info - { - uint16_t len; // bytes of this element, include this head - uint64_t pid; // process id - uint64_t ppid; // parent process id - uint64_t start; // started time in ns from 1970-01-01 00:00:00 - uint64_t mem; // memory usage, in bytes - uint64_t cpu_clk; // cpu clock - char path_name[4]; - }proc[1]; - - STRUCT_CONSTRUCTOR(_proc_info) -}PROCINFO, * LPPROCINFO; -#pragma pack(pop) - -//////////////////////////////////////////////////////////////////////////////////////////////// -// configurations ... -// -// 1 - App has whole set, group definitions -// -// 2 - device provides sub-set, or a customizing item -// diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/referer.h b/device/gxx-linux/testusb/usb-rk3399/src/common/referer.h deleted file mode 100644 index 368e6bd..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/referer.h +++ /dev/null @@ -1,187 +0,0 @@ -#pragma once - -// Objects life management -// -// created on 2022-11-29 -// - -// #include -#include -#include - -#if defined(WIN32) || defined(_WIN64) -#define WAIT_INFINITE INFINITE -#define FSEEK _fseeki64 -#define FTELL _ftelli64 -#define USER_DIR "LOCALAPPDATA" -#define PATH_SEPARATOR "\\" - -struct _time_val -{ - time_t tv_sec; /* Seconds. */ - time_t tv_usec; /* Microseconds. */ -}; -typedef struct _time_val TIMEV; - -struct timezone -{ - int tz_minuteswest; /* Minutes west of GMT. */ - int tz_dsttime; /* Nonzero if DST is ever in effect. */ -}; -extern int gettimeofday(TIMEV* tv, struct timezone* tz); -#else -#include -#include -#include -typedef struct timeval TIMEV; -#define WAIT_INFINITE 0 -#define FSEEK fseek -#define FTELL ftell -#define USER_DIR "HOME" -#define PATH_SEPARATOR "/" - -#endif - -#define ALIGN_INT(val, n) ((((val) + (n) - 1) / (n)) * (n)) - -#define SIZE_KB(n) ((n) * 1024) -#define SIZE_MB(n) SIZE_KB((n) * 1024) -#define SIZE_GB(n) SIZE_MB((n) * 1024) - -#define SEC_2_MS(s) ((s) * 1000) -#define MSEC_2_US(ms) ((ms) * 1000) -#define USEC_2_NS(us) ((us) * 1000) -#define SEC_2_US(s) MSEC_2_US(SEC_2_MS(s)) -#define SEC_2_NS(s) USEC_2_NS(MSEC_2_US(SEC_2_MS(s))) -#define MSEC_2_NS(ms) USEC_2_NS(MSEC_2_US(ms)) - -#define RETURN_ENUM_STR(v, e) \ - if(v == e) \ - return #e; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -typedef std::mutex MUTEX; -typedef std::lock_guard LOCKER; - -// object life referer -// -// derived from 'refer' if your class used in multi-threads -// -class refer -{ - volatile int32_t ref_; - MUTEX mutex_; - -protected: - refer(); - virtual ~refer(); - - virtual void on_born(void); - virtual void on_dead(void); - -public: - virtual int32_t add_ref(void); - virtual int32_t release(void); -}; - -class chronograph -{ - TIMEV bgn_; - -public: - chronograph(); - ~chronograph(); - - static bool now(TIMEV* tv); - static bool now(uint64_t* seconds, uint64_t* u_seconds); - static std::string now(bool with_ms = true/*whether with milliseconds*/); // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false - -public: - uint64_t elapse_s(void); - uint64_t elapse_ms(void); - uint64_t elapse_us(void); - void reset(void); -}; - -template -class thread_pool : public refer -{ - typedef struct _thrd - { - uint32_t id; - std::shared_ptr thread; - }THRD; - T* obj_; - std::vector threads_; - uint32_t id_; - - -public: - thread_pool(T* obj) : obj_(obj), id_(1) - {} - -protected: - virtual ~thread_pool() - {} - -public: - template - uint32_t thread_new(void(T::* thrd)(Args ...), Args ... args) // return thread ID (not pthread_t), used in thread_stop function - { - THRD t; - - t.id = id_++; - t.thread.reset(new std::thread(thrd, obj_, args ...)); - threads_.push_back(t); - - return t.id; - } - bool thread_stop(uint32_t id = -1) - { - bool ret = true; - if (id == -1) - { - for (auto& v : threads_) - { - if (v.thread.get() && v.thread->joinable()) - v.thread->join(); - v.thread.reset(); - } - threads_.clear(); - } - else - { - ret = false; - for (int i = 0; i < threads_.size(); ++i) - { - if (threads_[i].id == id) - { - ret = true; - if (threads_[i].thread.get() && threads_[i].thread->joinable()) - threads_[i].thread->join(); - threads_[i].thread.reset(); - threads_.erase(threads_.begin() + i); - break; - } - } - } - - return ret; - } -}; - - -template -T swap_half(T v) -{ - T mask = (1 << (sizeof(T) * 4)) - 1, - h = v & mask; - - v >>= sizeof(T) * 4; - v &= mask; - h <<= sizeof(T) * 4; - v |= h; - - return v; -} diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/sys_util.cpp b/device/gxx-linux/testusb/usb-rk3399/src/common/sys_util.cpp deleted file mode 100644 index e06b2d1..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/sys_util.cpp +++ /dev/null @@ -1,854 +0,0 @@ -#include "sys_util.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log_util.h" - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// sys utility - -namespace sys_util -{ - static bool find_module(const char* path, bool is_dir, void* param) - { - std::string* para = (std::string*)param; - - if (para[0].empty()) - { - const char* now = getenv("PWD"); - bool found = strstr(path, now) == path; - - if(found) - { - found = path[strlen(now)] == '/' && strstr(path + strlen(now) + 1, "/") == nullptr; - } - if(found || para[1].empty()) - para[1] = path; - - return !found; - } - else - { - const char* name = strrchr(path, '/'); - if (name++ == nullptr) - name = path; - if (strstr(name, para[0].c_str())) - { - para[1] = path; - - return false; - } - - return true; - } - } - typedef struct _enum_proc_cb - { - bool process; - bool(*on_found)(uint64_t pid, const char* path_name, void* param); - void* param; - }ENPROCCB, * LPENPROCCB; - static bool found_process(const char* path, bool is_dir, void* param) - { - LPENPROCCB cb = (LPENPROCCB)param; - const char* id = strrchr(path, '/'); - uint64_t pid = 0; - std::string path_name(""); - - if (id++ == nullptr) - { - id = path; - } - while (*id) - { - if (*id < '0' || *id > '9') - break; - - pid *= 10; - pid += *id - '0'; - id++; - } - if (*id || pid == 0) - return true; - - if (cb->process) - { - path_name = get_module_path(nullptr, pid); - id = path_name.c_str(); - } - else - { - // get start address of pid to path_name - id = 0; - } - - return cb->on_found(pid, id, cb->param); - } - static bool on_stack_line_read(char* line, void* param) - { - LPENPROCCB cb = (LPENPROCCB)param; - std::string m(line); - uint64_t off = 0; - size_t pos = m.find("]"); - - if (pos++ != std::string::npos) - m.erase(0, pos); - sys_util::trim_left(m); - pos = m.find("+0x"); - if (pos != std::string::npos) - { - off = from_hex_str(m.c_str() + pos + 3); - m.erase(pos); - } - - return cb->on_found(off, m.c_str(), cb->param); - } - - int32_t enum_modules(bool(*on_found)(const char* path_module_name, bool is_dir, void* param),// return false to stop enumeratin - void* param, // user defined data, passed into callback on_found - unsigned pid // process id, -1 is self - ) // return errno - { - char path[128] = { 0 }; - - if (pid == -1) - pid = getpid(); - sprintf(path, "/proc/%u/map_files/", pid); - - return enum_files(path, on_found, param, false); - } - - int32_t enum_files(const char* dir, // dir path - bool(*on_found)(const char* path_name, bool is_dir, void* param), // return false to stop enumeratin - void* param // user defined data, passed into callback on_found - , bool recursive - ) // return errno - { - int32_t ret = 0; - DIR* pdir = nullptr; - struct dirent* ent = nullptr; - - pdir = opendir(dir); - if (!pdir) - return errno; - - while ((ent = readdir(pdir))) - { - if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) - continue; - - std::string file(dir); - - file += "/"; - file += ent->d_name; - if ((ent->d_type & DT_DIR) == 0) - { - file = read_link(file.c_str()); - if(file.empty()) - file = std::string(dir) + "/" + ent->d_name; - } - if (!on_found(file.c_str(), ent->d_type & DT_DIR, param)) - { - ret = 0x5e17; - break; - } - - if ((ent->d_type & DT_DIR) && recursive) - { - std::string sub(dir); - sub += "/"; - sub += ent->d_name; - ret = enum_files(sub.c_str(), on_found, param, recursive); - if (ret == 0x5e17) - break; - } - } - closedir(pdir); - - return ret == 0x5e17 ? 0 : ret; - } - - int32_t enum_processes(bool(*on_found)(uint64_t pid, const char* path_name, void* param), void* param) - { - ENPROCCB cb; - - cb.on_found = on_found; - cb.param = param; - cb.process = true; - - return enum_files("/proc", found_process, &cb, false); - } - uint32_t enum_threads(uint64_t pid, bool(*on_found)(uint64_t tid, void* start_addr, void* param), void* param) - { - ENPROCCB cb; - - cb.process = false; - cb.param = param; - *(void**)&cb.on_found = *(void**)&on_found; - - return enum_files(("/proc/" + std::to_string(pid) + "/task").c_str(), found_process, &cb, false); - } - uint32_t get_thread_callstack(uint64_t pid, uint64_t tid, bool(*on_found)(uint64_t off, const char* module, void* param), void* param) - { - ENPROCCB cb; - - cb.process = false; - cb.param = param; - *(void**)&cb.on_found = *(void**)&on_found; - - return read_line(("/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/stack").c_str(), on_stack_line_read, &cb); - } - uint32_t read_line(const char* file, bool(*on_line)(char* line, void* param), void* param) - { - FILE* src = fopen(file, "rb"); - int err = 0; - - if (!src) - return errno; - - size_t ll = 1024; - char* line = new char[ll]; - while (fgets(line, ll - 1, src)) - { - if (!on_line(line, param)) - break; - - memset(line, 0, ll); - } - err = errno; - delete[] line; - fclose(src); - - return err; - } - - std::string get_module_path(const char* module_name, unsigned pid) // get module full path, nullptr is for main-exe - { - std::string param[] = { module_name ? module_name : "", "" }; - - enum_modules(find_module, param, pid); - - return param[1]; - } - std::string read_link(const char* lnk) - { - char path[512] = { 0 }; - - readlink(lnk, path, sizeof(path) - 1); - - return path; - } - size_t get_page_size(void) - { - size_t size = sysconf(_SC_PAGESIZE); - - if (size < 1024 || (size & 0x0fe0000ff)) // nKB && < 16MB - size = getpagesize(); - - return size; - } - bool create_folder(const char* dir) - { - bool ret = mkdir(dir, S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST; - - if(errno == ENOENT) - { - std::string path(dir), cur(""); - size_t pos = path.find("/", 1); - - while(pos != std::string::npos) - { - ret = mkdir(path.substr(0, pos).c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST; - if(!ret) - { - printf("mkdir(%s) = %d(%s)\n", path.substr(0, pos).c_str(), errno, strerror(errno)); - break; - } - pos = path.find("/", pos + 1); - } - if(ret) - ret = mkdir(path.c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0; - } - - return ret; - } - - int32_t get_memory_info(uint64_t* total, uint64_t* available) - { - if (!total && !available) - return 0; - - char line[128] = { 0 }; - FILE* src = fopen("/proc/meminfo", "rb"); - int32_t count = total && available ? 2 : 1; - unsigned long val = 0; - - if (!src) - return log_cls::log_when_err(-1, "fopen('/proc/meminfo', 'rb')", LOG_LEVEL_FATAL); - - while (fgets(line, sizeof(line) - 1, src)) - { - if (sscanf(line, "MemTotal: %ld", &val)) - { - if (total) - { - *total = val * 1024; - if (--count == 0) - break; - } - } - else if (sscanf(line, "MemFree: %ld", &val)) - { - if (available) - { - *available = val * 1024; - if (--count == 0) - break; - } - } - } - - fclose(src); - - return 0; - } - std::string format_readable_bytes(uint64_t bytes) - { - std::string str("\0", 80); - - if (bytes >= SIZE_GB(1)) - { - double v = bytes * 1.0f / (SIZE_GB(1)); - size_t pos = 0; - - sprintf(&str[0], "%.2fGB", v); - pos = str.find("."); - while (pos > 3) - { - pos -= 3; - str.insert(pos, ","); - } - } - else if (bytes >= SIZE_MB(1)) - { - double v = bytes * 1.0f / (SIZE_MB(1)); - sprintf(&str[0], "%.2fMB", v); - } - else if (bytes >= SIZE_KB(1)) - { - double v = bytes * 1.0f / (SIZE_KB(1)); - sprintf(&str[0], "%.2fKB", v); - } - else - { - sprintf(&str[0], "%uB", (unsigned)bytes); - } - - return str; - } - std::string get_command_output(const char* cmd, uint16_t max_line_len, bool one_line) - { - FILE* src = popen(cmd, "r"); - std::string ret(""); - - if (src) - { - char* buf = new char[max_line_len + 4]; - if (buf) - { - memset(buf, 0, max_line_len + 4); - fgets(buf, max_line_len, src); - ret = buf; - while (!one_line && fgets(buf, max_line_len, src)) - ret += "\n" + std::string(buf); - - delete[] buf; - } - - pclose(src); - } - - return ret; - } - int get_disk_size(const char* path, uint64_t* total, uint64_t* avail, uint64_t* block_size) - { - std::string dir(path ? path : ""); - struct statfs disk; - size_t pos = dir.rfind('/'); - - if (dir.empty() || dir[0] == '.' || pos == std::string::npos) - { - char self[256] = { 0 }; - - if (readlink("/proc/self/exe", self, sizeof(self) - 1) == -1) - return errno; - - dir = self; - } - pos = dir.rfind('/'); - if (pos != std::string::npos && pos > 0) - dir.erase(pos); - - if (statfs(dir.c_str(), &disk) == -1) - return errno; - - if (total) - *total = disk.f_blocks * disk.f_bsize; - if (avail) - *avail = disk.f_bsize * disk.f_bavail; - if (block_size) - *block_size = disk.f_bsize; - - return 0; - } - - static bool is_char_in(const char* str, char ch) - { - if (ch == 0) - return false; - - while (*str) - { - if (*str++ == ch) - return true; - } - - return false; - } - bool trim_left(std::string& str, const char* space) - { - int off = 0; - - for (; off < str.length(); ++off) - { - if (!is_char_in(space, str[off])) - break; - } - if (off) - str.erase(0, off); - - return off > 0; - } - bool trim_right(std::string& str, const char* space) - { - int off = str.length() - 1; - - for (; off >= 0; --off) - { - if (!is_char_in(space, str[off])) - break; - } - if (off < str.length() - 1) - { - str.erase(off + 1); - return true; - } - - return false; - } - uint64_t from_hex_str(const char* hex, const char** end) - { - uint64_t val = 0; - - for (int i = 0; i < 16; ++i) - { - if (*hex >= '0' && *hex <= '9') - { - val <<= 4; - val += *hex - '0'; - } - else if (*hex >= 'a' && *hex <= 'f') - { - val <<= 4; - val += *hex - 'a' + 10; - } - else if (*hex >= 'A' && *hex <= 'F') - { - val <<= 4; - val += *hex - 'A' + 10; - } - else - { - break; - } - hex++; - } - - if (end) - *end = hex; - - return val; - } - - static uint64_t from_dec_str(const char* str, const char** end) - { - uint64_t val = 0; - - for(int i = 0; *str && i < 19; ++i, ++str) - { - if(*str >= '0' && *str <= '9') - { - val *= 10; - val += *str - '0'; - } - else - break; - } - if(end) - *end = str; - - return val; - } - static uint64_t from_oct_str(const char* str, const char** end) - { - uint64_t val = 0; - - for(int i = 0; *str && i < 21; ++i, ++str) - { - if(*str >= '0' && *str <= '7') - { - val *= 8; - val += *str - '0'; - } - else - break; - } - if(end) - *end = str; - - return val; - } - static uint64_t from_bin_str(const char* str, const char** end) - { - uint64_t val = 0; - - for(int i = 0; *str && i < 64; ++i, ++str) - { - if(*str >= '0' && *str <= '1') - { - val *= 2; - val += *str - '0'; - } - else - break; - } - if(end) - *end = str; - - return val; - } - uint64_t to_int(const char* str, const char** end) - { - if(!str || *str == 0) - { - if(end) - *end = str; - - return 0; - } - - if(strstr(str, "0x") == str) - return from_hex_str(str + 2, end); - - if(str[strlen(str) - 1] == 'h' || str[strlen(str) - 1] == 'H') - return from_hex_str(str, end); - if(str[strlen(str) - 1] == 'o' || str[strlen(str) - 1] == 'O') - return from_oct_str(str, end); - if(str[strlen(str) - 1] == 'b' || str[strlen(str) - 1] == 'B') - return from_bin_str(str, end); - - bool hex = false; - for(int i = 0; str[i]; ++i) - { - if(str[i] < '0') - break; - if(str[i] > '9') - { - if((str[i] >= 'a' && str[i] <= 'f') || - (str[i] >= 'A' && str[i] <= 'F')) - hex = true; - break; - } - } - - return hex ? from_hex_str(str, end) : from_dec_str(str, end); - } - - /* iconv_open language options: - - Europe: - ASCII, ISO-8859-{1,2,3,4,5,7,9,10,13,14,15,16}, KOI8-R, KOI8-U, KOI8-RU, - CP{1250,1251,1252,1253,1254,1257}, CP{850,866}, - Mac{Roman,CentralEurope,Iceland,Croatian,Romania}, - Mac{Cyrillic,Ukraine,Greek,Turkish}, Macintosh - - Semitic: - ISO-8859-{6,8}, CP{1255,1256}, CP862, Mac{Hebrew,Arabic} - - Janpanese: - EUC-JP, SHIFT-JIS, CP932, ISO-2022-JP, ISO-2022-JP-2, ISO-2022-JP-1 - - Chinese: - EUC-CN, HZ, GBK, GB18030, EUC-TW, BIG5, CP950, BIG5-HKSCS, ISO-2022-CN, ISO-2022-CN-EXT - - Korean: - EUC-KR, CP949, ISO-2022-KR, JOHAB - - Armenian: - ARMSCII-8 - - Georgian: - Georgian-Academy, Georgian-PS - - Thai: - TIS-620, CP874, MacThai - - Laos: - MuleLao-1, CP1133 - - Vietnam: - VISCII, TCVN, CP1258 - - Special: - HP-ROMAN8, NEXTSTEP - - Full Unicode: - UTF-8 - UCS-2, UCS-2BE, UCS-2LE - UCS-4, UCS-4BE, UCS-4LE - UTF-16, UTF-16BE, UTF-16LE - UTF-32, UTF-32BE, UTF-32LE - UTF-7 - JAVA - */ - std::string transform_between_gbk_and_utf8(const char* in, bool to_utf8, int *err) - { - size_t len = strlen(in) + 8, ol = len * 2; - char *buf = (char*)malloc(len), *oper = buf, *out = nullptr, *oper1 = nullptr; - iconv_t conv; - - memset(buf, 0, len); - strcpy(buf, in); - if(to_utf8) - conv = iconv_open("UTF-8", "GBK"); - else - conv = iconv_open("GBK", "UTF-8"); - if(conv == (iconv_t)-1) - { - if(err) - *err = errno; - - free(buf); - - return ""; - } - - oper1 = out = (char*)malloc(ol); - memset(out, 0, ol); - len -= 8; - if(iconv(conv, &oper, &len, &oper1, &ol)) - { - if(err) - *err = errno; - } - else if(err) - *err = 0; - - std::string ret(out); - - free(buf); - free(out); - iconv_close(conv); - - return std::move(ret); - } - std::string transform_between_utf16_and_utf8(const char* in, size_t bytes, bool to_utf8) - { - static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - std::string ret(""); - - if(to_utf8) - { - unsigned short *uc = *(unsigned short**)&in, val = 0; - for(size_t i = 0; i < bytes / 2; ++i, ++uc) - { - val = *uc; - if ((*uc>=0xDC00 && *uc<=0xDFFF) || *uc==0) break; /* check for invalid. */ - - if (*uc>=0xD800 && *uc<=0xDBFF) /* UTF16 surrogate pairs. */ - { - unsigned short uc2 = uc[1]; - if (uc2 < 0xDC00 || uc2 > 0xDFFF) break; /* invalid second-half of surrogate. */ - val = 0x10000 + (((*uc & 0x3FF) << 10) | (uc2 & 0x3FF)); - } - - int len = 4; - char buf[4] = {0}, *ptr2 = buf; - if (val<0x80) len=1;else if (val<0x800) len=2;else if (val<0x10000) len=3; ptr2+=len; - - switch (len) { - case 4: *--ptr2 =((val | 0x80) & 0xBF); val >>= 6; - case 3: *--ptr2 =((val | 0x80) & 0xBF); val >>= 6; - case 2: *--ptr2 =((val | 0x80) & 0xBF); val >>= 6; - case 1: *--ptr2 =(val | firstByteMark[len]); - } - ret += std::string(buf, len); - } - } - else - { - char* unic = (char*)malloc(strlen(in) * 3 + 8); - unsigned char * cur = (unsigned char*)unic; - - while (*cur = *in++) - { - if ((*cur & 0x0f0) == 0x0e0) - { - if (((unsigned char)in[0] & 0x0c0) == 0x80 && - ((unsigned char)in[1] & 0x0c0) == 0x80) - { - const char* hex = "0123456789ABCDEF"; - unsigned short us = *cur & 0x0f; - us <<= 6; - us += in[0] & 0x3f; - us <<= 6; - us += in[1] & 0x3f; - - *cur++ = '\\'; - *cur++ = 'u'; - cur[3] = hex[us & 0x0f]; - us >>= 4; - cur[2] = hex[us & 0x0f]; - us >>= 4; - cur[1] = hex[us & 0x0f]; - us >>= 4; - cur[0] = hex[us & 0x0f]; - cur += 3; - in += 2; - } - } - cur++; - } - *cur++ = 0; - ret = std::string(unic, (char*)cur - unic); - free(unic); - } - - return std::move(ret); - } - - std::string to_abs_path(const char* base, const char* rel_path) - { - if(*rel_path == '/') - return rel_path; - - std::string b(base), r(rel_path); - size_t pos = 0; - - while(b.length() && b[b.length() - 1] == '/') - b.erase(b.length() - 1); - - while(r[0] == '.') - { - if(r[1] == '/') - r.erase(0, 2); - else if(r[1] == '.' && r[2] == '/') - { - pos = b.rfind('/'); - if(pos == std::string::npos) - break; - b.erase(pos); - r.erase(0, 3); - } - else - break; - } - - b += "/" + r; - - return std::move(b); - } - std::string to_rel_path(const char* base, const char* abs_path) - { - if(*abs_path != '/') - return abs_path; - - std::string rel(""), b(base), a(abs_path); - size_t pos = 0; - - while(b.length() && b[b.length() - 1] == '/') - b.erase(b.length() - 1); - - while(a.find(b) == std::string::npos) - { - rel += "../"; - pos = b.rfind('/'); - if(pos == 0) - break; - b.erase(pos - 1); - } - if(rel.empty()) - rel = "./"; - - return std::move(rel + a); - } - - const char* pick_simple_block(const char* head, char end) - { - const char* tail = head + 1; - int cnt = 1; - - while(*tail) - { - if(*tail == end) - { - cnt--; - if(cnt == 0) - break; - } - else if(*tail == *head) - { - cnt++; - } - else if(*tail == '\\') - { - tail++; - if(*tail == 0) - break; - } - tail++; - } - - return cnt == 0 ? tail : nullptr; - } - - bool now(struct timeval* tv) - { - struct timezone tz = { 0 }; - bool ok = gettimeofday(tv, &tz) == 0; - - // tv->tv_sec -= 60 * tz.tz_minuteswest; - - return ok; - } - uint64_t thread_id(const std::thread::id& tid) - { - return (uint64_t)pthread_self(); - - std::stringstream ss; - - ss << tid; - - return std::stoull(ss.str()); - } -} - diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/sys_util.h b/device/gxx-linux/testusb/usb-rk3399/src/common/sys_util.h deleted file mode 100644 index b89c9e4..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/sys_util.h +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -// Objects life management -// -// created on 2022-11-29 -// - -#include -#include - - -namespace sys_util -{ - int32_t enum_modules(bool(*on_found)(const char* path_module_name, bool is_dir, void* param),// return false to stop enumeratin - void* param, // user defined data, passed into callback on_found - unsigned pid = -1 // process id, -1 is self - ); // return errno - - int32_t enum_files(const char* dir // dir path - , bool(*on_found)(const char* path_name, bool is_dir, void* param)// return false to stop enumeratin - , void* param // user defined data, passed into callback on_found - , bool recursive = true // walk recursive - ); // return errno - int32_t enum_processes(bool(*on_found)(uint64_t pid, const char* path_name, void* param), void* param); - uint32_t enum_threads(uint64_t pid, bool(*on_found)(uint64_t tid, void* start_addr, void* param), void* param); - uint32_t get_thread_callstack(uint64_t pid, uint64_t tid, bool(*on_found)(uint64_t off, const char* module, void* param), void* param); - uint32_t read_line(const char* file, bool(*on_line)(char* line, void* param), void* param); - - std::string get_module_path(const char* module_name = nullptr - , unsigned pid = -1); // get module full path, nullptr is for main-exe - std::string read_link(const char* lnk); - size_t get_page_size(void); - bool create_folder(const char* dir); - - // Function: pick single-line info file data, return count of set-value variable - // - // Parameters: file - full path of local file - // - // line_max - max bytes of a line in file 'file' - // - // fmt - line fromat string, e.g. "model name : %60[\x20-\x7e]", "MemoryTotal: %ld", "address sizes : %d bits physical, %d bits virtual", ... - // - // args - variable list - // - // Return: count of the variable which got the value - template - int32_t get_inf_file_data(const char* file, size_t line_max, const char* fmt, Args ... args) - { - std::string buf("\0", line_max + 8); - FILE* src = fopen(file, "rb"); - int32_t count = 0; - - if (!src) - return 0; - - while (fgets(&buf[0], line_max, src)) - { - count = sscanf(&buf[0], fmt, args ...); - if (count > 0) - break; - } - fclose(src); - - return count; - } - - int32_t get_memory_info(uint64_t* total, uint64_t* available); - std::string format_readable_bytes(uint64_t bytes); // convert to readable text: 512B, 1.21KB, 1.10MB, 3.45GB, 1,234.56GB ... - std::string get_command_output(const char* cmd, uint16_t max_line_len = 256, bool one_line = true); - int get_disk_size(const char* path, uint64_t* total, uint64_t* avail, uint64_t* block_size); - - // trim string, return whether space trimmed - bool trim_left(std::string& str, const char* space = " \t"); - bool trim_right(std::string& str, const char* space = " \t"); - uint64_t from_hex_str(const char* hex, const char** end = nullptr); // convert 0x100 to 256. parameter 'end' to receive the stopped position - - // Function: convert number string to integer, support hex, dec, oct and bin - // - // Parameter: str - number string. - // 0x.../...h: as hexadecimal - // ...o: as octonary - // ...b: as binary - // ...: as decimal, or as hexadecimal if has hex letter - // - // end - to receive the ending point when covert over - // - // Return: integer, default is ZERO, you should check the ending point when this value returned - uint64_t to_int(const char* str, const char** end = nullptr); - - std::string transform_between_gbk_and_utf8(const char* in, bool to_utf8, int* err = nullptr); - std::string transform_between_utf16_and_utf8(const char* in, size_t bytes, bool to_utf8); - - std::string to_abs_path(const char* base, const char* rel_path); - std::string to_rel_path(const char* base, const char* abs_path); - - // Function: pick simple block in pair chars - // - // Parameter: head - beginning of the string, and the first character is the beginning char - // - // end - ending character of the block - // - // Return: the last positoin of the block (*ret = end), or nullptr if not matched - const char* pick_simple_block(const char* head, char end); - - uint64_t thread_id(const std::thread::id& tid); -} diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/usb_io.cpp b/device/gxx-linux/testusb/usb-rk3399/src/common/usb_io.cpp deleted file mode 100644 index fa9e35c..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/usb_io.cpp +++ /dev/null @@ -1,790 +0,0 @@ -#include "usb_io.h" - -#include -#include -#include -#include -#include "../../inc/logs_out.h" -#include "sys_util.h" -#include "log_util.h" - -// #define TEST - -async_usb_gadget::async_usb_gadget(usb_gadget* gadget, std::function unhandled_ep0 - , std::function cmd_handler) - : gadget_(gadget), unhandled_ep0_(unhandled_ep0), handle_cmd_(cmd_handler), threads_(new thread_pool(this)) -{ - wait_ep0_ = new linux_event("wait_ep0"); - memset((void*)&status_, 0, sizeof(status_)); - memset((void*)&ep0_status_, 0, sizeof(ep0_status_)); - - threads_->thread_new(&async_usb_gadget::thread_pump_task); - thread_ep0_id_ = threads_->thread_new(&async_usb_gadget::thread_read_ep0); - threads_->thread_new(&async_usb_gadget::thread_check_ep0_status); -} - -async_usb_gadget::~async_usb_gadget() -{ - stop(); - if(thread_restart_id_ != -1) - threads_->thread_stop(thread_restart_id_); - threads_->release(); - wait_ep0_->release(); -} - -const char* async_usb_gadget::ep0_status_desc(int ep0_status, char* unk_buf/*>= 20 bytes*/) -{ - RETURN_ENUM_STR(ep0_status, EP0_STATUS_IDLE); - RETURN_ENUM_STR(ep0_status, EP0_STATUS_READ_DATA); - RETURN_ENUM_STR(ep0_status, EP0_STATUS_READ_INVAL_DATA); - RETURN_ENUM_STR(ep0_status, EP0_STATUS_HANDLE_CMD); - - sprintf(unk_buf, "Unknown status (%d)", ep0_status); - - return unk_buf; -} -void async_usb_gadget::set_ep0_status(uint32_t id, int status, int data) -{ - LOCKER lock(ep0_status_lock_); - - ep0_status_.id = id; - ep0_status_.status = status; - ep0_status_.data = data; -} -void async_usb_gadget::get_ep0_status(uint32_t* id, int* status, int* data) -{ - LOCKER lock(ep0_status_lock_); - - if (id) - *id = ep0_status_.id; - if (status) - *status = ep0_status_.status; - if (data) - *data = ep0_status_.data; -} - -int async_usb_gadget::wait_fd_event(int fd, int to_ms) -{ - struct timeval timeout, *pto = NULL; - fd_set read_set; - int ret = 0; - - FD_ZERO(&read_set); - FD_SET(fd, &read_set); - if (to_ms != -1) - { - timeout.tv_sec = to_ms / 1000; - timeout.tv_usec = (to_ms % 1000) * 1000; - pto = &timeout; - } - ret = select(fd + 1, &read_set, NULL, NULL, pto); - - return ret; -} - -int async_usb_gadget::open_bulk(void) -{ - int err = 0; - if (gadget_->ep_handles[EP_DESCRIPTOR_IN] < 0) - { - gadget_->ep_handles[EP_DESCRIPTOR_IN] = open(gadget_->ep_path[EP_DESCRIPTOR_IN], O_RDWR); - err = gadget_->ep_handles[EP_DESCRIPTOR_IN] == -1 ? errno : 0; - log_cls::log(LOG_LEVEL_ALL, "Open endpoint(%s) = %d (err = %d)\n", gadget_->ep_path[EP_DESCRIPTOR_IN], gadget_->ep_handles[EP_DESCRIPTOR_IN], err); - if(gadget_->ep_handles[EP_DESCRIPTOR_IN] >= 0) - { - status_.in_status = BULK_STATUS_IDLE; - thread_bulk_in_id_ = threads_->thread_new(&async_usb_gadget::thread_write_bulk); - } - } - if (gadget_->ep_handles[EP_DESCRIPTOR_OUT] < 0) - { - gadget_->ep_handles[EP_DESCRIPTOR_OUT] = open(gadget_->ep_path[EP_DESCRIPTOR_OUT], O_RDWR); - err = gadget_->ep_handles[EP_DESCRIPTOR_OUT] == -1 ? errno : 0; - log_cls::log(LOG_LEVEL_ALL, "Open endpoint(%s) = %d (err = %d)\n", gadget_->ep_path[EP_DESCRIPTOR_OUT], gadget_->ep_handles[EP_DESCRIPTOR_OUT], err); - if(gadget_->ep_handles[EP_DESCRIPTOR_OUT] >= 0) - { - status_.out_status = BULK_STATUS_IDLE; - thread_bulk_out_id_ = threads_->thread_new(&async_usb_gadget::thread_read_bulk); - } - } - - return 0; -} -int async_usb_gadget::close_bulk(bool incl_ep0) -{ - dyn_mem_ptr mem = nullptr; - data_source_ptr data = nullptr; - int cnt = 0; - - sent_que_.quit(); - cmd_que_.quit(); - - if (gadget_->ep_handles[EP_DESCRIPTOR_IN] >= 0) - { - cnt = close(gadget_->ep_handles[EP_DESCRIPTOR_IN]); - status_.in_status = BULK_STATUS_NOT_START; - log_cls::log(LOG_LEVEL_ALL, "close BULK-IN endpoint %d = %d\n", gadget_->ep_handles[EP_DESCRIPTOR_IN], cnt); - } - if (gadget_->ep_handles[EP_DESCRIPTOR_OUT] >= 0) - { - cnt = close(gadget_->ep_handles[EP_DESCRIPTOR_OUT]); - status_.out_status = BULK_STATUS_NOT_START; - log_cls::log(LOG_LEVEL_ALL, "close BULK-OUT endpoint %d = %d\n", gadget_->ep_handles[EP_DESCRIPTOR_OUT], cnt); - } - gadget_->ep_handles[EP_DESCRIPTOR_IN] = gadget_->ep_handles[EP_DESCRIPTOR_OUT] = -1; - if (thread_bulk_in_id_ >= 0) - { - sent_que_.quit(); - log_cls::log(LOG_LEVEL_ALL, "Stop BULK-IN thread.\n"); - threads_->thread_stop(thread_bulk_in_id_); - } - if (thread_bulk_out_id_ >= 0) - { - log_cls::log(LOG_LEVEL_ALL, "Stop BULK-OUT thread.\n"); - threads_->thread_stop(thread_bulk_out_id_); - } - thread_bulk_out_id_ = thread_bulk_in_id_ = -1; - - if(incl_ep0) - { - log_cls::log(LOG_LEVEL_ALL, "Close usb device (EP0) %d.\n", gadget_->usb_device); - close(gadget_->usb_device); - gadget_->usb_device = -1; - if(thread_ep0_id_ >= 0) - threads_->thread_stop(thread_ep0_id_); - thread_ep0_id_ = -1; - } - - cnt = 0; - while (cmd_que_.take(mem, false)) - { - mem->release(); - cnt++; - } - status_.task_cnt = 0; - log_cls::log(LOG_LEVEL_ALL, "Clear %d command(s) in command-queue\n", cnt); - - cnt = 0; - while (sent_que_.take(data, false)) - { - data->release(); - cnt++; - } - status_.bytes_to_sent = status_.packets_to_sent = 0; - log_cls::log(LOG_LEVEL_ALL, "Clear %d reply(s) in sent-queue\n", cnt); - - return 0; -} -int async_usb_gadget::handle_ctrl_message(dyn_mem_ptr data) -{ - struct usb_functionfs_event* pev = (struct usb_functionfs_event*)data->ptr(); - dyn_mem_ptr reply = nullptr; - - switch (pev->type) - { - case FUNCTIONFS_ENABLE: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS ENABLE\n"); - if (gadget_->ep_handles[EP_DESCRIPTOR_IN] < 0) - { - open_bulk(); - } - break; - case FUNCTIONFS_DISABLE: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS DISABLE\n"); - close_bulk(); - break; - case FUNCTIONFS_SETUP: - // log_cls::log(LOG_LEVEL_ALL, "%s: control(type-%x, req-%x, ind-%x, val-%x, len-%x)\n", chronograph::now().c_str() - // , pev->u.setup.bRequestType, pev->u.setup.bRequest, pev->u.setup.wIndex, pev->u.setup.wValue, pev->u.setup.wLength); - data->add_ref(); - reply = handle_ctrl_setup(data); - break; - case FUNCTIONFS_BIND: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS BIND\n"); - break; - case FUNCTIONFS_UNBIND: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS UNBIND\n"); - break; - case FUNCTIONFS_SUSPEND: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS SUSPEND\n"); - break; - case FUNCTIONFS_RESUME: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS RESUME\n"); - break; - } - - if (pev->u.setup.bRequestType & USB_DIR_IN) - { - // if host need data back, and reply is null, we send nonsense data back ... - if (!reply) - { - reply = dyn_mem::memory(pev->u.setup.wLength + sizeof(uint16_t)); - reply->set_len(pev->u.setup.wLength); - for (int i = 0; i <= pev->u.setup.wLength / sizeof(uint16_t); ++i) - ((uint16_t*)reply->ptr())[i] = 0x0baad; - } - - int s = write(gadget_->usb_device, reply->ptr(), reply->get_rest()); - reply->release(); - } - - data->release(); - return 0; -} -dyn_mem_ptr async_usb_gadget::handle_ctrl_setup(dyn_mem_ptr data) -{ - struct usb_functionfs_event* pev = (struct usb_functionfs_event*)data->ptr(); - bool handled = (pev->u.setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR; - dyn_mem_ptr reply = nullptr; - uint32_t err = 0; - - if(handled) - { - switch (pev->u.setup.bRequest) - { - case USB_REQ_EP0_GET_PROTO_VER: - reply = dyn_mem::memory(sizeof(short)); - *(short*)reply->ptr() = PROTOCOL_VER; - reply->set_len(sizeof(short)); - break; - case USB_REQ_EP0_GET_STATUS: - reply = dyn_mem::memory(sizeof(struct _ep0_reply)); - { - reply->put((void*)&status_, sizeof(status_)); - } - break; - case USB_REQ_EP0_RESET_BULK: - reply = dyn_mem::memory(sizeof(uint32_t)); - if(!reset_bulk_) - { - log_cls::log(LOG_LEVEL_DEBUG, "Reset bulk ...\n"); - reset_bulk_ = true; - wait_ep0_->trigger(); - } - else - err = EBUSY; - reply->put(&err, sizeof(err)); - break; - default: - handled = false; - } - } - if(!handled && unhandled_ep0_) - { - log_cls::log(LOG_LEVEL_ALL, "EP0 event(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) has not handled by user business.\n" - , pev->u.setup.bRequestType, pev->u.setup.bRequest, pev->u.setup.wValue, pev->u.setup.wIndex, pev->u.setup.wLength); - reply = unhandled_ep0_(pev); - } - - data->release(); - - return reply; -} -int async_usb_gadget::inner_write_bulk(data_source_ptr data, int* err) -{ - unsigned char* ptr = data->ptr(); - size_t bulk_size = gadget_->ep_config[EP_DESCRIPTOR_IN]->ep_desc[0].ep_desc.wMaxPacketSize, - total = data->get_rest(), off = 0, size = total > bulk_size ? bulk_size : total; - int w = 0; - - if(data->is_memory_block()) - { - while(!reset_bulk_ && (w = write(gadget_->ep_handles[EP_DESCRIPTOR_IN], ptr + off, size)) > 0) - { - off += w; - status_.bytes_to_sent -= w; - if(off >= total) - break; - if(off + bulk_size < total) - size = bulk_size; - else - size = total - off; - } - if(w <= 0 && err) - *err = errno; - } - else - { - dyn_mem_ptr buf = dyn_mem::memory(bulk_size); - uint32_t len = bulk_size; - - if(err) - *err = 0; - total = 0; - while(!reset_bulk_ && (w = data->fetch_data(buf->ptr(), &len)) == 0) - { - ptr = buf->ptr(); - off = 0; - w = write(gadget_->ep_handles[EP_DESCRIPTOR_IN], ptr + off, len); - if(w > 0 && w + off == len) - status_.bytes_to_sent -= w; - while(!reset_bulk_ && w > 0 && w + off < len) - { - status_.bytes_to_sent -= w; - total += w; - off += w; - w = write(gadget_->ep_handles[EP_DESCRIPTOR_IN], ptr + off, len - off); - } - - if(w <= 0) - { - if(err) - *err = errno; - break; - } - else - total += w; - - if(data->get_rest() == 0) - break; - len = bulk_size; - } - buf->release(); - off = total; - log_cls::log(LOG_LEVEL_ALL, "Finished in send large content with %u bytes.\n", total); - } - - return off; -} - -void async_usb_gadget::thread_check_ep0_status(void) -{ - uint32_t id = 0, prev_id = 0; - int status = EP0_STATUS_IDLE, prev_s = status; - int data = 0, prev_d = 0; - int cnt = 0; - char buf[40] = { 0 }; - - while (run_) - { - if (wait_ep0_->wait(1000)) - { - if (run_) - { - // only ONE task to do - reset bulk ... - if (thread_restart_id_ != -1) - threads_->thread_stop(thread_restart_id_); - thread_restart_id_ = threads_->thread_new(&async_usb_gadget::thread_restart_bulk); - } - } - else - { - get_ep0_status(&id, &status, &data); - if (id == prev_id) - { - if (prev_s == status && prev_d == data && status != EP0_STATUS_IDLE) - { - cnt++; - if (cnt >= 5) - { - log_cls::log(LOG_LEVEL_ALL, "-xxx- EP0 blocked in status %s !!!\n", ep0_status_desc(status, buf)); - - // do something to resolve this problem here ... - } - } - else - { - prev_s = status; - prev_d = data; - cnt = 0; - } - } - else - { - prev_id = id; - prev_s = status; - prev_d = data; - cnt = 0; - } - } - } -} -void async_usb_gadget::thread_read_ep0(void) -{ - struct timeval timeout; - int headl = sizeof(struct usb_functionfs_event), - datal = 128, // gadget_->usb_config->dev_desc.bMaxPacketSize0, - ret = 0; - dyn_mem_ptr mem = dyn_mem::memory(headl + datal); - uint8_t* ptr = mem->ptr(); - uint32_t recycles = 0; - struct usb_functionfs_event* pe = (struct usb_functionfs_event*)ptr; - - log_cls::log(LOG_LEVEL_ALL, "EP0 monitoring thread(%p of id %lx) started ...\n", &async_usb_gadget::thread_read_ep0, sys_util::thread_id(std::this_thread::get_id())); - while(run_) - { - set_ep0_status(++recycles, EP0_STATUS_IDLE, 0); - - ret = wait_fd_event(gadget_->usb_device); - if( ret <= 0 ) - { - log_cls::log(LOG_LEVEL_ALL, "select EP0(%d) failed: %d(%s)\n", gadget_->usb_device, errno, strerror(errno)); - break; - } - - // timeout.tv_sec = 0; - ret = read(gadget_->usb_device, ptr, headl); - if (ret < 0) - { - log_cls::log(LOG_LEVEL_ALL, "read EP0 failed: %d(%s)\n", errno, strerror(errno)); - break; - } - - bool good = true; - if(pe->u.setup.bRequestType & USB_DIR_IN) - mem->set_len(headl); - else - { - if (pe->u.setup.wLength > datal) - { - good = false; - log_cls::log(LOG_LEVEL_ALL, "EP0 data too long(%d > %d), we will discard this packet(0x%x, 0x%x, 0x%x, 0x%x)!\n", pe->u.setup.wLength, datal, - pe->u.setup.bRequestType, pe->u.setup.bRequest, pe->u.setup.wValue, pe->u.setup.wIndex); - - // we read-out whole data here ... - int rest = pe->u.setup.wLength; - while (rest > 0) - { - set_ep0_status(recycles, EP0_STATUS_READ_INVAL_DATA, rest); - read(gadget_->usb_device, ptr + headl, rest > datal ? datal : rest); - rest -= datal; - } - } - else - { - set_ep0_status(recycles, EP0_STATUS_READ_DATA, pe->u.setup.wLength); - read(gadget_->usb_device, ptr + headl, pe->u.setup.wLength); - mem->set_len(headl + pe->u.setup.wLength); - } - } - if (good) - { - set_ep0_status(recycles, EP0_STATUS_HANDLE_CMD, pe->u.setup.bRequest); - mem->add_ref(); - handle_ctrl_message(mem); - } - } - mem->release(); - log_cls::log(LOG_LEVEL_ALL, "EP0 monitoring thread exited.\n"); -} -void async_usb_gadget::thread_read_bulk(void) -{ - log_cls::log(LOG_LEVEL_ALL, "thread_read_bulk(%p of id %lx) started ...\n", &async_usb_gadget::thread_read_bulk, sys_util::thread_id(std::this_thread::get_id())); - size_t bulk_size = gadget_->ep_config[EP_DESCRIPTOR_OUT]->ep_desc[0].ep_desc.wMaxPacketSize; - uint32_t cnt_0 = 0; - - while(run_) - { - dyn_mem_ptr buf(dyn_mem::memory(bulk_size)); - int l = 0; - - // l = wait_fd_event(gadget_->ep_handles[EP_DESCRIPTOR_OUT]); - // if (l <= 0) - // { - // log_cls::log(LOG_LEVEL_ALL, "wait bulk-out event failed: %d\n", errno); - // break; - // } - - status_.out_status = BULK_STATUS_IO; - l = read(gadget_->ep_handles[EP_DESCRIPTOR_OUT], buf->ptr(), bulk_size); - if(l <= 0) - { - buf->release(); - if(errno) - { - log_cls::log(LOG_LEVEL_ALL, "read bulk failed: %d(%s)\n", errno, strerror(errno)); - status_.out_status = BULK_STATUS_ERROR; - status_.out_err = errno; - break; - } - else - { - cnt_0++; - // log_cls::log(LOG_LEVEL_ALL, "read bulk with 0 byte.\n"); - } - } - else if (reset_bulk_ || !run_) - { - // if(cnt_0) - // { - // log_cls::log(LOG_LEVEL_ALL, "read bulk with 0 byte - %u time(s).\n", cnt_0); - // cnt_0 = 0; - // } - log_cls::log(LOG_LEVEL_ALL, "thread_pump_task do reset-bulk ...\n"); - buf->release(); - if(!run_) - break; - } - else - { - // if(cnt_0) - // { - // log_cls::log(LOG_LEVEL_ALL, "read bulk with 0 byte - %u time(s).\n", cnt_0); - // cnt_0 = 0; - // } - status_.out_status = BULK_STATUS_IDLE; - buf->set_len(l); - cmd_que_.save(buf, true); - } - } - if(status_.out_status == BULK_STATUS_IDLE) - status_.out_status = reset_bulk_ ? BULK_STATUS_RESET : BULK_STATUS_NOT_START; - - log_cls::log(LOG_LEVEL_ALL, "thread_read_bulk exited.\n"); -} -void async_usb_gadget::thread_write_bulk(void) -{ - log_cls::log(LOG_LEVEL_ALL, "thread_write_bulk(%p of id %lx) started ...\n", &async_usb_gadget::thread_write_bulk, sys_util::thread_id(std::this_thread::get_id())); - - status_.in_status = BULK_STATUS_IDLE; - while(run_) - { - data_source_ptr data; - int err = 0; - - if(sent_que_.take(data, true)) - { - if(reset_bulk_) - { - log_cls::log(LOG_LEVEL_ALL, "thread_write_bulk do reset-bulk ...\n"); - data->release(); - continue; - } - - status_.packets_to_sent = sent_que_.size(); - status_.bytes_to_sent = data->get_rest(); - status_.in_status = BULK_STATUS_IO; - inner_write_bulk(data, &err); - status_.in_status = BULK_STATUS_IDLE; - status_.bytes_to_sent = 0; - data->release(); - if(err) - { - log_cls::log(LOG_LEVEL_ALL, "write bulk failed: %d(%s)\n", errno, strerror(errno)); - status_.in_status = BULK_STATUS_ERROR; - status_.in_err = err; - break; - } - } - // if (reset_bulk_) - // break; - } - if(status_.in_status == BULK_STATUS_IDLE) - status_.in_status = reset_bulk_ ? BULK_STATUS_RESET : BULK_STATUS_NOT_START; - - log_cls::log(LOG_LEVEL_ALL, "thread_write_bulk exited.\n"); -} -void async_usb_gadget::thread_pump_task(void) -{ - log_cls::log(LOG_LEVEL_ALL, "thread_pump_task(%p of id %lx) started ...\n", &async_usb_gadget::thread_pump_task, sys_util::thread_id(std::this_thread::get_id())); - - dyn_mem_ptr prev = nullptr, data = nullptr, reply = nullptr; - bool in_err_statu = false; - uint32_t required = 0, used = 0, restore_err_cnt = 0, max_que = 0; - data_holder *dh = nullptr; - LPPACK_BASE pack = nullptr; - uint64_t total_size = 0; - - while(run_) - { - data = nullptr; - if(cmd_que_.take(data, true) && data) - { - status_.task_cnt = cmd_que_.size(); - if(max_que < status_.task_cnt) - max_que = status_.task_cnt; - - if(reset_bulk_) - { - data->release(); - } - else - { - if (in_err_statu) - { - - } - if(prev) - { - log_cls::log(LOG_LEVEL_ALL, "Combine partial packet with length %u and %u ...\n", prev->get_rest(), data->get_rest()); - *prev += *data; - data->release(); - data = prev; - prev = nullptr; - } - - do - { - packet_data_base_ptr pack_data = nullptr; - data_source_ptr ds = nullptr; - - if(dh == nullptr) - { - if (data->get_rest() < sizeof(PACK_BASE)) - break; - else - { - pack = (LPPACK_BASE)data->ptr(); - status_.task_cmd = pack->cmd; - status_.task_pack_id = pack->pack_id; - reply = handle_cmd_(data, &used, &pack_data); - if(pack_data) - { - dh = dynamic_cast(pack_data); - if(!dh) - { - ds = dynamic_cast(pack_data); - if(!ds) - pack_data->release(); - } - else - total_size = 0; - } - } - } - else - { - uint32_t len = data->get_rest(); - int err = 0; // - -#ifndef TEST - err = dh->put_data(data->ptr(), &len); -#endif - if(len < data->get_rest()) - { - log_cls::log(LOG_LEVEL_WARNING, "Put partial data %u/%u! at +%08X with error %d\n", len, data->get_rest(), total_size, err); - } - total_size += len; -#ifdef TEST - { - dyn_mem_ptr back = dyn_mem::memory(data->get_rest()); - back->put(data->ptr(), data->get_rest()); - write_bulk(back); // test -> reply this data back ... - status_.task_required_bytes = dh->get_required() - total_size; - } -#endif - if(dh->is_complete() || err -#ifdef TEST - || total_size >= dh->get_required() -#endif - ) - { - reply = dyn_mem::memory(sizeof(PACK_BASE)); - pack = (LPPACK_BASE)reply->ptr(); - BASE_PACKET_REPLY(*pack, dh->get_packet_command() + 1, dh->get_packet_id(), err); - reply->set_len(sizeof(PACK_BASE)); - - log_cls::log(LOG_LEVEL_ALL, "Finished received file with error(Max queue size is %u): %d, total size = 0x%x\n", max_que, err, total_size); - - dh->release(); - dh = nullptr; - } - used = len; - - if (err) - { - in_err_statu = true; - restore_err_cnt = 0; - } - } - - // first reply the packet ... - if(reply) - { - write_bulk(dynamic_cast(reply)); - reply->release(); - reply = nullptr; - } - - // second send appendix data ... - if (ds) - { - write_bulk(ds); - ds->release(); - ds = nullptr; - } - -#ifndef TEST - status_.task_required_bytes = dh ? dh->get_required() : 0; -#endif - if(status_.task_required_bytes == 0) - status_.task_cmd = status_.task_pack_id = 0; - - data->used(used); - }while(used && data->get_rest()); - - if(data->get_rest()) - prev = data; - else - data->release(); - } - } - if (reset_bulk_) - { - log_cls::log(LOG_LEVEL_ALL, "thread_pump_task do reset-bulk (max command queue size is %u in previous turn) ...\n", max_que); - max_que = 0; - if (prev) - { - prev->release(); - prev = nullptr; - } - if (dh) - { - dh->release(); - dh = nullptr; - } - status_.task_cmd = status_.task_pack_id = status_.task_required_bytes = 0; - } - } - if(prev) - prev->release(); - if (data) - data->release(); - if (reply) - reply->release(); - if (dh) - dh->release(); - - log_cls::log(LOG_LEVEL_ALL, "thread_pump_task exited.\n"); -} -void async_usb_gadget::thread_restart_bulk(void) -{ - dyn_mem_ptr data; - while(cmd_que_.take(data, false)) - data->release(); - - data_source_ptr src; - while(sent_que_.take(src, false)) - src->release(); - - sent_que_.quit(); - cmd_que_.quit(); - - // close_bulk(); - while(status_.in_status != BULK_STATUS_IDLE || status_.out_status != BULK_STATUS_IO || status_.task_cmd) - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - - // open_bulk(); - // cmd_que_.quit(); - reset_bulk_ = false; - log_cls::log(LOG_LEVEL_ALL, "reset bulk completed.\n"); -} - -int async_usb_gadget::stop(void) -{ - run_ = false; - close_bulk(true); - threads_->thread_stop(); - - return 0; -} -int async_usb_gadget::write_bulk(data_source_ptr data) -{ - if(!reset_bulk_) - { - data->add_ref(); - sent_que_.save(data, true); - } - - return 0; -} diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/usb_io.h b/device/gxx-linux/testusb/usb-rk3399/src/common/usb_io.h deleted file mode 100644 index 45df339..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/usb_io.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once - -// Objects IO -// -// created on 2023-03-10 - -#include "referer.h" -#include "packet.h" -#include "ipc_util.h" -#include "data.h" - -#include -#include -#include -#include -#include "../../inc/usb_gadget.h" - - -// callback proto -// -// parameters: usb_functionfs_event* - the function event ptr -// -// dyn_mem_ptr - the packet buffer, read-only -// -// uint32_t* - to return how many data in bytes the handler consumed -// -// normally, the value should be PACK_BASE::payload_len, i.e. the handler consume all data of an entire packet -// -// when invalid packet, suggest use the entire data -// -// packet_data_base_ptr* - return data_holder or data_source or nullptr -// -// data_holder: the packet/command need more data than dyn_mem_ptr provides to complete the business. such as 'write a large file' -// -// data_source: the reply content may be a large data (a large file content) -// -// return value of all routines is the reply packet, nullptr if the packet need not reply -// -#define FUNCTION_PROTO_UNHANDLED_EP0 dyn_mem_ptr(struct usb_functionfs_event*) - - -typedef union _setup_request_type // subclass of usb_ctrlrequest::bRequestType -{ - uint8_t type8; - struct - { - uint8_t receiver : 5; // 0 - device; 1 - interface; 2 - endpoint; 3 - other; others - reserved - uint8_t category : 2; // 0 - standard; 1 - class; 2 - vendor/user defined; 3 - reserved - uint8_t direction : 1; // 0 - host to device; 1 - device to host - }; -}REQTYPE; - - - -class async_usb_gadget : public refer -{ - thread_pool* threads_ = nullptr; - volatile bool run_ = true; - volatile bool reset_bulk_ = false; - usb_gadget *gadget_ = nullptr; - int thread_ep0_id_ = -1; - int thread_bulk_in_id_ = -1; - int thread_bulk_out_id_ = -1; - int thread_restart_id_ = -1; - volatile EP0REPLYSTATUS status_; - safe_fifo cmd_que_; - safe_fifo sent_que_; - - enum - { - EP0_STATUS_IDLE = 0, - EP0_STATUS_READ_DATA, // ep0_statu::data is rest data len - EP0_STATUS_READ_INVAL_DATA, // ep0_statu::data is rest data len - EP0_STATUS_HANDLE_CMD, - }; - volatile struct _ep0_statu - { - uint32_t id; - int status; - int data; - }ep0_status_; - MUTEX ep0_status_lock_; - linux_event *wait_ep0_; - - std::function unhandled_ep0_; - std::function handle_cmd_; - - const char* ep0_status_desc(int ep0_status, char* unk_buf/*>= 40 bytes*/); - void set_ep0_status(uint32_t id, int status, int data); - void get_ep0_status(uint32_t* id, int* status, int* data); - - int wait_fd_event(int fd, int to_ms = -1); - - int open_bulk(void); - int close_bulk(bool incl_ep0 = false); - int handle_ctrl_message(dyn_mem_ptr data); - dyn_mem_ptr handle_ctrl_setup(dyn_mem_ptr data); // user command ... - int inner_write_bulk(data_source_ptr data, int* err = nullptr); - - void thread_check_ep0_status(void); - void thread_read_ep0(void); - void thread_read_bulk(void); - void thread_write_bulk(void); - void thread_pump_task(void); - void thread_restart_bulk(void); - -public: - async_usb_gadget(usb_gadget* gadget, std::function unhandled_ep0 = std::function() - , std::function cmd_handler = std::function()); - -protected: - ~async_usb_gadget(); - -public: - int stop(void); - int write_bulk(data_source_ptr data); -}; - diff --git a/device/gxx-linux/testusb/usb-rk3399/src/logs_out.cpp b/device/gxx-linux/testusb/usb-rk3399/src/logs_out.cpp deleted file mode 100644 index 363d1ba..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/logs_out.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * CAMTP Responder - * Copyright (c) 2020 Holdtecs Technologies - * - * CAMTP Responder 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.0 of the License, or (at your option) any later version. - * - * CAMTP Responder 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 version 3 for more details. - * - * You should have received a copy of the GNU General Public License - * along with CAMTP Responder; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file logs_out.c - * @brief log output functions - * @author *** - */ - -#include "buildconf.h" - -#include -#include -#include - -#include "logs_out.h" - -void timestamp(char * timestr, int maxsize) -{ - time_t ltime; - struct tm * local_time; - - ltime = time(NULL); - timestr[0] = 0; - - local_time = localtime(<ime); - - snprintf(timestr, maxsize, "%.2d:%.2d:%.2d",local_time->tm_hour, local_time->tm_min, local_time->tm_sec ); -} - -#ifdef DEBUG -int is_printable_char(unsigned char c) -{ - int i; - unsigned char specialchar[]={"&#{}()|_@=$!?;+*-"}; - - if( (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') ) - { - return 1; - } - - i = 0; - while(specialchar[i]) - { - if(specialchar[i] == c) - { - return 1; - } - - i++; - } - - return 0; -} - -void printbuf(void * buf,int size) -{ - #define PRINTBUF_HEXPERLINE 16 - #define PRINTBUF_MAXLINE_SIZE ((3*PRINTBUF_HEXPERLINE)+1+PRINTBUF_HEXPERLINE+2) - - int i,j; - unsigned char *ptr = (unsigned char*)buf; - char tmp[8]; - char str[PRINTBUF_MAXLINE_SIZE]; - - memset(str, ' ', PRINTBUF_MAXLINE_SIZE); - str[PRINTBUF_MAXLINE_SIZE-1] = 0; - - j = 0; - for(i=0;i -#include "logs_out.h" -#include -#include -#include -#include "usbstring.h" -#include "default_cfg.h" -#include -#include -#include -#include - -#ifdef ASYNC_EP -#include "log_util.h" -#endif - -#define CONFIG_VALUE 1 -#define USB_MAX_PACKAGE_LENGTH_FILE "/opt/usbpkgconfig" - -// extern int errno; -static int get_system_output(const char *cmd) -{ - printf("shell command: %s", cmd); - int ret = 0; - FILE *fp=NULL; - fp = popen(cmd, "r"); - if (fp) - { - char buf[1024] = {0}; - int rv = fread(buf, 1, sizeof(buf) - 1, fp); - printf(" -- (%d)\n", rv); - if(buf[0]) - { - printf(buf); - printf("\n"); - } - pclose(fp); - } - else - { - printf("popen failed\n"); - ret = errno; - } - - return ret; -} - -static struct usb_gadget_strings strings = { - .language = 0x0409, /* en-us */ - .strings = 0, -}; - -typedef struct camtp_device_status_ { - uint16_t wLength; - uint16_t wCode; -}camtp_device_status; - -static std::shared_ptr bulk_sent_; -static std::shared_ptr bulk_read_; -static std::shared_ptr int_sent_; - -const int UsbDevice::cacheSize = 64*1024; - - -int camtp_load_config_file(camtp_ctx * context, const char * conffile) -{ - int err = 0; - FILE * f; - char line[MAX_CFG_STRING_SIZE]; - - memset((void*)&context->usb_cfg,0x00, sizeof(camtp_usb_cfg)); - - // Set default config - strncpy(context->usb_cfg.usb_device_path, USB_DEV, MAX_CFG_STRING_SIZE); - strncpy(context->usb_cfg.usb_endpoint_in, USB_EPIN, MAX_CFG_STRING_SIZE); - strncpy(context->usb_cfg.usb_endpoint_out, USB_EPOUT, MAX_CFG_STRING_SIZE); - strncpy(context->usb_cfg.usb_endpoint_intin, USB_EPINTIN, MAX_CFG_STRING_SIZE); - strncpy(context->usb_cfg.usb_string_manufacturer, MANUFACTURER, MAX_CFG_STRING_SIZE); - strncpy(context->usb_cfg.usb_string_product, PRODUCT, MAX_CFG_STRING_SIZE); - strncpy(context->usb_cfg.usb_string_serial, SERIALNUMBER, MAX_CFG_STRING_SIZE); - strncpy(context->usb_cfg.usb_string_version, "Rev A", MAX_CFG_STRING_SIZE); - strncpy(context->usb_cfg.usb_string_interface, "camtp", MAX_CFG_STRING_SIZE); - - context->usb_cfg.usb_vendor_id = USB_DEV_VENDOR_ID; - context->usb_cfg.usb_product_id = USB_DEV_PRODUCT_ID; - context->usb_cfg.usb_class = USB_DEV_CLASS; - context->usb_cfg.usb_subclass = USB_DEV_SUBCLASS; - context->usb_cfg.usb_protocol = USB_DEV_PROTOCOL; - context->usb_cfg.usb_dev_version = USB_DEV_VERSION; - std::ifstream fs(USB_MAX_PACKAGE_LENGTH_FILE); - int maxpackagesize =0; - fs >> maxpackagesize; - maxpackagesize<=0?maxpackagesize = 512:maxpackagesize; - printf("vid::pid - %04X::%04X\n", context->usb_cfg.usb_vendor_id, context->usb_cfg.usb_product_id); - - //printf("MAX_PACKET_SIZE = %d \n",maxpackagesize); - context->usb_cfg.usb_max_packet_size = maxpackagesize; - //context->usb_cfg.usb_max_packet_size = MAX_PACKET_SIZE; - context->usb_cfg.usb_functionfs_mode = USB_FFS_MODE; - - context->usb_cfg.wait_connection = 0; - context->usb_cfg.loop_on_disconnect = 0; - - context->usb_cfg.show_hidden_files = 1; - - context->usb_cfg.val_umask = -1; - - PRINT_MSG("USB Device path : %s",context->usb_cfg.usb_device_path); - PRINT_MSG("USB In End point path : %s",context->usb_cfg.usb_endpoint_in); - PRINT_MSG("USB Out End point path : %s",context->usb_cfg.usb_endpoint_out); - PRINT_MSG("USB Event End point path : %s",context->usb_cfg.usb_endpoint_intin); - PRINT_MSG("USB Max packet size : 0x%X bytes",context->usb_cfg.usb_max_packet_size); - - PRINT_MSG("Manufacturer string : %s",context->usb_cfg.usb_string_manufacturer); - PRINT_MSG("Product string : %s",context->usb_cfg.usb_string_product); - PRINT_MSG("Serial string : %s",context->usb_cfg.usb_string_serial); - PRINT_MSG("Firmware Version string : %s", context->usb_cfg.usb_string_version); - PRINT_MSG("Interface string : %s",context->usb_cfg.usb_string_interface); - - PRINT_MSG("USB Vendor ID : 0x%.4X",context->usb_cfg.usb_vendor_id); - PRINT_MSG("USB Product ID : 0x%.4X",context->usb_cfg.usb_product_id); - PRINT_MSG("USB class ID : 0x%.2X",context->usb_cfg.usb_class); - PRINT_MSG("USB subclass ID : 0x%.2X",context->usb_cfg.usb_subclass); - PRINT_MSG("USB Protocol ID : 0x%.2X",context->usb_cfg.usb_protocol); - PRINT_MSG("USB Device version : 0x%.4X",context->usb_cfg.usb_dev_version); - - if(context->usb_cfg.usb_functionfs_mode) - { - PRINT_MSG("USB FunctionFS Mode"); - } - else - { - PRINT_MSG("USB GadgetFS Mode"); - } - - PRINT_MSG("Wait for connection : %i",context->usb_cfg.wait_connection); - PRINT_MSG("Loop on disconnect : %i",context->usb_cfg.loop_on_disconnect); - PRINT_MSG("Show hidden files : %i",context->usb_cfg.show_hidden_files); - if(context->usb_cfg.val_umask >= 0) - { - PRINT_MSG("File creation umask : %03o",context->usb_cfg.val_umask); - } - else - { - PRINT_MSG("File creation umask : System default umask"); - } - - return err; -} - -void UsbDevice::fill_if_descriptor(camtp_ctx * ctx, usb_gadget * usbctx, struct usb_interface_descriptor * desc) -{ - memset(desc,0,sizeof(struct usb_interface_descriptor)); - - desc->bLength = sizeof(struct usb_interface_descriptor); - desc->bDescriptorType = USB_DT_INTERFACE; //!< nick - desc->bInterfaceNumber = 0; - desc->iInterface = 1; - desc->bAlternateSetting = 0; - desc->bNumEndpoints = 3; - - desc->bInterfaceClass = ctx->usb_cfg.usb_class; - desc->bInterfaceSubClass = ctx->usb_cfg.usb_subclass; - desc->bInterfaceProtocol = ctx->usb_cfg.usb_protocol; - if( ctx->usb_cfg.usb_functionfs_mode ) - { - desc->iInterface = 1; - } - else - { - desc->iInterface = STRINGID_INTERFACE; - } - - log_cls::log(LOG_LEVEL_ALL, "fill_if_descriptor:\n"); - PRINT_DEBUG_BUF(desc, sizeof(struct usb_interface_descriptor)); - - return; -} - -void UsbDevice::fill_ep_descriptor(camtp_ctx * ctx, usb_gadget * usbctx,struct usb_endpoint_descriptor_no_audio * desc,int index,unsigned int flags) -{ - memset(desc,0,sizeof(struct usb_endpoint_descriptor_no_audio)); - - desc->bLength = USB_DT_ENDPOINT_SIZE; - desc->bDescriptorType = USB_DT_ENDPOINT; - - if(flags & EP_OUT_DIR) - desc->bEndpointAddress = USB_DIR_OUT | (index); - else - desc->bEndpointAddress = USB_DIR_IN | (index); - - if(flags & EP_BULK_MODE) - { - desc->bmAttributes = USB_ENDPOINT_XFER_BULK; - desc->wMaxPacketSize = ctx->usb_cfg.usb_max_packet_size; - //printf("desc->wMaxPacketSize = %d \n",desc->wMaxPacketSize); - } - else - { - desc->bmAttributes = USB_ENDPOINT_XFER_INT; - desc->wMaxPacketSize = 64; // HS size 64 - desc->bInterval = 6; - } - -#if defined(CONFIG_USB_SS_SUPPORT) - if(flags & EP_SS_MODE) - { - ep_cfg_descriptor * ss_descriptor; - - ss_descriptor = (ep_cfg_descriptor *)desc; - - ss_descriptor->ep_desc_comp.bLength = sizeof(struct usb_ss_ep_comp_descriptor); - ss_descriptor->ep_desc_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; - if(flags & EP_BULK_MODE){ - ss_descriptor->ep_desc_comp.bMaxBurst = 15; - ss_descriptor->ep_desc_comp.wBytesPerInterval = 0x00; - }else{ - ss_descriptor->ep_desc_comp.bMaxBurst = 0; - ss_descriptor->ep_desc_comp.wBytesPerInterval = 64;//0x1c - } - } -#endif - - log_cls::log(LOG_LEVEL_ALL, "fill_ep_descriptor:\n"); - PRINT_DEBUG_BUF(desc, sizeof(struct usb_endpoint_descriptor_no_audio)); - - return; -} - -int UsbDevice::add_usb_string(usb_gadget * usbctx, int id, char * string) -{ - int i; - - i = 0; - - while( i < MAX_USB_STRING ) - { - if( !usbctx->stringtab[i].id ) - { - usbctx->stringtab[i].id = id; - if(string) - { - usbctx->stringtab[i].str = (char*)malloc(strlen(string) + 1); - if(usbctx->stringtab[i].str) - { - memset(usbctx->stringtab[i].str,0,strlen(string) + 1); - strcpy(usbctx->stringtab[i].str,string); - return i; - } - else - { - usbctx->stringtab[i].id = 0; - return -2; - } - } - else - { - return i; - } - } - i++; - } - - return -1; -} - -void UsbDevice::fill_config_descriptor(camtp_ctx * ctx , usb_gadget * usbctx,struct usb_config_descriptor * desc,int total_size, int hs) -{ - memset(desc,0,sizeof(struct usb_config_descriptor)); - - desc->bLength = sizeof(struct usb_config_descriptor); - desc->bDescriptorType = USB_DT_CONFIG; - desc->wTotalLength = desc->bLength + total_size; - desc->bNumInterfaces = 1; - desc->bConfigurationValue = CONFIG_VALUE; - if(hs) - desc->iConfiguration = STRINGID_CONFIG_HS; - else - desc->iConfiguration = STRINGID_CONFIG_LS; - desc->bmAttributes = USB_CONFIG_ATT_ONE; - desc->bMaxPower = 1; - - log_cls::log(LOG_LEVEL_ALL, "fill_config_descriptor: (Total Len : %u + %d = %d)\n", (unsigned int) sizeof(struct usb_config_descriptor), total_size, desc->wTotalLength); - PRINT_DEBUG_BUF(desc, sizeof(struct usb_config_descriptor)); - - return; -} - -void UsbDevice::fill_dev_descriptor(camtp_ctx * ctx, usb_gadget * usbctx,struct usb_device_descriptor * desc) -{ - memset(desc,0,sizeof(struct usb_device_descriptor)); - - desc->bLength = USB_DT_DEVICE_SIZE; - desc->bDescriptorType = USB_DT_DEVICE; - desc->bDeviceClass = ctx->usb_cfg.usb_class; - desc->bDeviceSubClass = ctx->usb_cfg.usb_subclass; - desc->bDeviceProtocol = ctx->usb_cfg.usb_protocol; - desc->idVendor = ctx->usb_cfg.usb_vendor_id; - desc->idProduct = ctx->usb_cfg.usb_product_id; - desc->bcdDevice = ctx->usb_cfg.usb_dev_version; // Version - // Strings - desc->iManufacturer = STRINGID_MANUFACTURER; - desc->iProduct = STRINGID_PRODUCT; - desc->iSerialNumber = STRINGID_SERIAL; - desc->bNumConfigurations = 1; // Only one configuration - - log_cls::log(LOG_LEVEL_ALL, "fill_dev_descriptor:\n"); - PRINT_DEBUG_BUF(desc, sizeof(struct usb_device_descriptor)); - - return; -} - -UsbDevice::UsbDevice(std::function handler, std::function call_back) -: b_connected(false) -, connect_call(call_back) -, usb_(nullptr) -{ - camtp_context.reset(new camtp_ctx); - memset(camtp_context.get(), 0, sizeof(camtp_ctx)); -#ifdef ASYNC_EP - log_cls::initialize(nullptr); - auto bulk_handle = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* required) -> dyn_mem_ptr - { - LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); - uint32_t consume = 0, want = 0; - - if(!used) - used = &consume; - *used = data->get_rest(); - - return handle_bulk_cmd(pack, used, required); - }; - - auto ctrl_unhandle = [&](struct usb_functionfs_event* pev) -> dyn_mem_ptr - { - return unhandled_ep0(pev); - }; - - thread_pool *t = new thread_pool(this); - t->thread_new(&UsbDevice::do_system_command, R"(echo linaro | sudo -S sh -c "echo fe900000.dwc3 > /opt/cfg/usb_gadget/g1/UDC")"); - camtp_load_config_file(camtp_context.get(), ""); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - usb_ctx = init_usb_camtp_gadget(camtp_context.get()); - if(usb_ctx && usb_ctx->usb_device >= 0) - { - get_system_output(R"(echo linaro | sudo -S sh -c "chmod 777 /dev/ffs-camtp -R")"); - init_eps(usb_ctx, camtp_context->usb_cfg.usb_functionfs_mode, false); - - usb_ = new async_usb_gadget(usb_ctx, ctrl_unhandle, bulk_handle); - } - t->thread_stop(); - t->release(); -#else - thread_main = std::move(std::thread(&UsbDevice::usb_main, this)); - get_system_output(R"(echo linaro | sudo -S sh -c "echo fe900000.dwc3 > /opt/cfg/usb_gadget/g1/UDC")"); -#endif - - //get_system_output(R"(echo linaro | sudo -S sh -c "echo ff580000.usb > /opt/cfg/usb_gadget/g1/UDC")"); - ctrl_handler = handler; - -} - -UsbDevice::~UsbDevice() -{ - pthread_cancel(thread_main.native_handle()); - if(usb_) - { - usb_->stop(); - usb_->release(); - } -} - -int UsbDevice::read_bulk(void *data, int size, int* err, bool full) -{ - int rcv = read(usb_ctx->ep_handles[EP_DESCRIPTOR_OUT], data, size, err, full); - - printf("read_bulk = %d\n", rcv); - - return rcv; -} - -int UsbDevice::write_bulk(void *data, int size, int* err) -{ - return write(usb_ctx->ep_handles[EP_DESCRIPTOR_IN], data, size, err); -} - -int UsbDevice::write_int(void *data, int size, int* err) -{ - return write(usb_ctx->ep_handles[EP_DESCRIPTOR_INT_IN], data, (unsigned char)size, err); -} - -int UsbDevice::write(int fd, void* data, size_t size, int* err) -{ - int writed = 0; - int writing = 0; - uint8_t* src = (uint8_t*)data; - do - { - writing = std::max(0, std::min(cacheSize, (int)(size - writed))); - writing = ::write(fd, src + writed, writing); - if(writing >= 0) - writed += writing; - else - { - printf("wrote(%d, %d) = %d(%s)\n", fd, size, errno, strerror(errno)); - if(err) - *err = errno; - break; - } - }while (writed != size); - - return writed; -} - -int UsbDevice::read(int fd, void* data, size_t size, int* err, bool full) -{ - int readed= 0; - int reading = 0; - uint8_t* buf = (uint8_t*)data; - do - { - reading = std::max(0, std::min(cacheSize, (int)(size - readed))); - reading = ::read(fd, buf + readed, reading); - if(reading > 0) - readed += reading; - else - { - if(err) - *err = errno; - printf("read error(%d): %s\n", errno, strerror(errno)); - break; - } - - }while (readed != size && full); - - return readed; -} - - void UsbDevice::abort_int() - { - ioctl(usb_ctx->ep_handles[EP_DESCRIPTOR_INT_IN], GADGETFS_FIFO_FLUSH); - } - -usb_gadget* UsbDevice::init_usb_camtp_gadget(camtp_ctx * ctx) -{ - usb_gadget * usbctx; - int cfg_size; - int ret,i; - ffs_strings ffs_str; - - usbctx = NULL; - - usbctx = (usb_gadget *)malloc(sizeof(usb_gadget)); - if(usbctx) - { - - memset(usbctx,0,sizeof(usb_gadget)); - - usbctx->usb_device = -1; - usbctx->thread_not_started = 1; - - i = 0; - while( i < EP_NB_OF_DESCRIPTORS ) - { - usbctx->ep_handles[i] = -1; - i++; - } - - add_usb_string(usbctx, STRINGID_MANUFACTURER, ctx->usb_cfg.usb_string_manufacturer); - add_usb_string(usbctx, STRINGID_PRODUCT, ctx->usb_cfg.usb_string_product); - add_usb_string(usbctx, STRINGID_SERIAL, ctx->usb_cfg.usb_string_serial); - add_usb_string(usbctx, STRINGID_CONFIG_HS, (char*)"High speed configuration"); - add_usb_string(usbctx, STRINGID_CONFIG_LS, (char*)"Low speed configuration"); - add_usb_string(usbctx, STRINGID_INTERFACE, ctx->usb_cfg.usb_string_interface); - add_usb_string(usbctx, STRINGID_MAX, NULL); - - strings.strings = usbctx->stringtab; - - usbctx->wait_connection = ctx->usb_cfg.wait_connection; - - for(i=0;i<3;i++) - { - usbctx->ep_config[i] = (ep_cfg*)malloc(sizeof(ep_cfg)); - if(!usbctx->ep_config[i]) - goto init_error; - - memset(usbctx->ep_config[i],0,sizeof(ep_cfg)); - } - - usbctx->ep_path[0] = ctx->usb_cfg.usb_endpoint_in; - usbctx->ep_path[1] = ctx->usb_cfg.usb_endpoint_out; - usbctx->ep_path[2] = ctx->usb_cfg.usb_endpoint_intin; - - usbctx->usb_device = open(ctx->usb_cfg.usb_device_path, O_RDWR|O_SYNC); - log_cls::log(LOG_LEVEL_ALL, "USB device: open(%s) = %d (%d)\n", ctx->usb_cfg.usb_device_path, usbctx->usb_device, usbctx->usb_device == -1 ? errno : 0); - // std::this_thread::sleep_for(std::chrono::milliseconds(15000)); - // printf("USB device: go on ^_^\n"); - - if (usbctx->usb_device <= 0) - { - PRINT_ERROR("init_usb_camtp_gadget : Unable to open %s (%m)", ctx->usb_cfg.usb_device_path); - goto init_error; - } - - cfg_size = sizeof(struct usb_interface_descriptor) + (sizeof(struct usb_endpoint_descriptor_no_audio) * 3); - - if( ctx->usb_cfg.usb_functionfs_mode ) - { - // FunctionFS mode - - usbctx->usb_ffs_config = (usb_ffs_cfg *)malloc(sizeof(usb_ffs_cfg)); - if(!usbctx->usb_ffs_config) - goto init_error; - - memset(usbctx->usb_ffs_config,0,sizeof(usb_ffs_cfg)); - -#ifdef OLD_FUNCTIONFS_DESCRIPTORS // Kernel < v3.15 - usbctx->usb_ffs_config->magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC); -#else - usbctx->usb_ffs_config->magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2); - usbctx->usb_ffs_config->flags = htole32(0); - usbctx->usb_ffs_config->flags |= htole32(FUNCTIONFS_ALL_CTRL_RECIP); - -#ifdef CONFIG_USB_FS_SUPPORT - usbctx->usb_ffs_config->flags |= htole32(FUNCTIONFS_HAS_FS_DESC); -#endif - -#ifdef CONFIG_USB_HS_SUPPORT - usbctx->usb_ffs_config->flags |= htole32(FUNCTIONFS_HAS_HS_DESC); -#endif - -#ifdef CONFIG_USB_SS_SUPPORT - usbctx->usb_ffs_config->flags |= htole32(FUNCTIONFS_HAS_SS_DESC); -#endif - -#endif - usbctx->usb_ffs_config->length = htole32(sizeof(usb_ffs_cfg)); - -#ifdef CONFIG_USB_FS_SUPPORT - usbctx->usb_ffs_config->fs_count = htole32(1 + 3); - - fill_if_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_fs.if_desc); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_fs.ep_desc_in,1, EP_BULK_MODE | EP_IN_DIR); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_fs.ep_desc_out,2, EP_BULK_MODE | EP_OUT_DIR); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_fs.ep_desc_int_in,3, EP_INT_MODE | EP_IN_DIR); -#endif - -#ifdef CONFIG_USB_HS_SUPPORT - usbctx->usb_ffs_config->hs_count = htole32(1 + 3); - fill_if_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_hs.if_desc); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_hs.ep_desc_in,1, EP_BULK_MODE | EP_IN_DIR | EP_HS_MODE); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_hs.ep_desc_out,2, EP_BULK_MODE | EP_OUT_DIR | EP_HS_MODE); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_hs.ep_desc_int_in,3, EP_INT_MODE | EP_IN_DIR | EP_HS_MODE); -#endif - -#ifdef CONFIG_USB_SS_SUPPORT - usbctx->usb_ffs_config->ss_count = htole32(1 + (3*2)); - fill_if_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_ss.if_desc); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_ss.ep_desc_in,1, EP_BULK_MODE | EP_IN_DIR | EP_SS_MODE); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_ss.ep_desc_out,2, EP_BULK_MODE | EP_OUT_DIR | EP_SS_MODE); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_ss.ep_desc_int_in,3, EP_INT_MODE | EP_IN_DIR | EP_SS_MODE); -#endif - - log_cls::log(LOG_LEVEL_ALL, "init_usb_camtp_gadget :\n"); - PRINT_DEBUG_BUF(usbctx->usb_ffs_config, sizeof(usb_ffs_cfg)); - - ret = write(usbctx->usb_device, usbctx->usb_ffs_config, sizeof(usb_ffs_cfg)); - - if(ret != sizeof(usb_ffs_cfg)) - { - PRINT_ERROR("FunctionFS USB Config write error (%d != %zu)",ret,sizeof(usb_ffs_cfg)); - goto init_error; - } - - memset( &ffs_str, 0, sizeof(ffs_strings)); - ffs_str.header.magic = htole32(FUNCTIONFS_STRINGS_MAGIC); - ffs_str.header.length = htole32(sizeof(struct usb_functionfs_strings_head) + sizeof(uint16_t) + strlen(ctx->usb_cfg.usb_string_interface) + 1); - ffs_str.header.str_count = htole32(1); - ffs_str.header.lang_count = htole32(1); - ffs_str.code = htole16(0x0409); // en-us - strcpy(ffs_str.string_data,ctx->usb_cfg.usb_string_interface); - - log_cls::log(LOG_LEVEL_ALL, "write string :\n"); - PRINT_DEBUG_BUF(&ffs_str, sizeof(ffs_strings)); - - ret = write(usbctx->usb_device, &ffs_str, ffs_str.header.length); - - if( ret != ffs_str.header.length ) - { - PRINT_ERROR("FunctionFS String Config write error (%d != %zu)",ret,(size_t)ffs_str.header.length); - goto init_error; - } - } - else - { - usbctx->usb_config = (usb_cfg *)malloc(sizeof(usb_cfg)); - if(!usbctx->usb_config) - goto init_error; - - memset(usbctx->usb_config,0,sizeof(usb_cfg)); - - usbctx->usb_config->head = 0x00000000; - -#ifdef CONFIG_USB_FS_SUPPORT - fill_config_descriptor(ctx, usbctx, &usbctx->usb_config->cfg_fs, cfg_size, 0); - fill_if_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_fs.if_desc); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_fs.ep_desc_in,1, EP_BULK_MODE | EP_IN_DIR); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_fs.ep_desc_out,2, EP_BULK_MODE | EP_OUT_DIR); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_fs.ep_desc_int_in,3, EP_INT_MODE | EP_IN_DIR); -#endif - -#ifdef CONFIG_USB_HS_SUPPORT - fill_config_descriptor(ctx, usbctx, &usbctx->usb_config->cfg_hs, cfg_size, 1); - fill_if_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_hs.if_desc); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_hs.ep_desc_in,1, EP_BULK_MODE | EP_IN_DIR | EP_HS_MODE); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_hs.ep_desc_out,2, EP_BULK_MODE | EP_OUT_DIR | EP_HS_MODE); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_hs.ep_desc_int_in,3, EP_INT_MODE | EP_IN_DIR | EP_HS_MODE); -#endif - -#ifdef CONFIG_USB_SS_SUPPORT - fill_config_descriptor(ctx, usbctx, &usbctx->usb_config->cfg_ss, cfg_size, 1); - fill_if_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_ss.if_desc); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_ss.ep_desc_in,1, EP_BULK_MODE | EP_IN_DIR | EP_SS_MODE); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_ss.ep_desc_out,2, EP_BULK_MODE | EP_OUT_DIR | EP_SS_MODE); - fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_ss.ep_desc_int_in,3, EP_INT_MODE | EP_IN_DIR | EP_SS_MODE); -#endif - - fill_dev_descriptor(ctx, usbctx,&usbctx->usb_config->dev_desc); - - log_cls::log(LOG_LEVEL_ALL, "init_usb_camtp_gadget :\n"); - PRINT_DEBUG_BUF(usbctx->usb_config, sizeof(usb_cfg)); - - ret = write(usbctx->usb_device, usbctx->usb_config, sizeof(usb_cfg)); - - if(ret != sizeof(usb_cfg)) - { - PRINT_ERROR("GadgetFS USB Config write error (%d != %zu)",ret,sizeof(usb_cfg)); - goto init_error; - } - } - - log_cls::log(LOG_LEVEL_ALL, "init_usb_camtp_gadget : USB config done\n"); - printf("init usb ok!\n"); - - return usbctx; - } - -init_error: - PRINT_ERROR("init_usb_camtp_gadget init error !"); - - deinit_usb_camtp_gadget(usbctx); - - return 0; -} - -void UsbDevice::deinit_usb_camtp_gadget(usb_gadget * usbctx) -{ - int i; - - log_cls::log(LOG_LEVEL_ALL, "entering deinit_usb_camtp_gadget\n"); - - if( usbctx ) - { - usbctx->stop = 1; - - i = 0; - while( i < EP_NB_OF_DESCRIPTORS ) - { - - if( usbctx->ep_handles[i] >= 0 ) - { - log_cls::log(LOG_LEVEL_ALL, "Closing End Point %d...\n",i); - close(usbctx->ep_handles[i] ); - } - i++; - } - - if (usbctx->usb_device >= 0) - { - log_cls::log(LOG_LEVEL_ALL, "Closing usb device...\n"); - printf("close USB device(%d)\n", usbctx->usb_device); - close(usbctx->usb_device); - usbctx->usb_device = - 1; - } - - if( !usbctx->thread_not_started ) - { - log_cls::log(LOG_LEVEL_ALL, "Stopping USB Thread...\n"); - pthread_cancel (usbctx->thread); - pthread_join(usbctx->thread, NULL); - usbctx->thread_not_started = 1; - } - - if(usbctx->usb_config) - { - free(usbctx->usb_config); - usbctx->usb_config = 0; - } - - if(usbctx->usb_ffs_config) - { - free(usbctx->usb_ffs_config); - usbctx->usb_ffs_config = 0; - } - - for(i=0;i<3;i++) - { - if( usbctx->ep_config[i] ) - free( usbctx->ep_config[i] ); - } - - i = 0; - while( i < MAX_USB_STRING ) - { - if( usbctx->stringtab[i].str ) - { - free ( usbctx->stringtab[i].str ); - } - i++; - } - - free( usbctx ); - } - - log_cls::log(LOG_LEVEL_ALL, "leaving deinit_usb_camtp_gadget\n"); -} - -void UsbDevice::usb_main() -{ - int retcode = 0; - int loop_continue = 0; - camtp_load_config_file(camtp_context.get(), ""); - - loop_continue = camtp_context->usb_cfg.loop_on_disconnect; - - do - { - usb_ctx = init_usb_camtp_gadget(camtp_context.get()); - get_system_output(R"(echo linaro | sudo -S sh -c "chmod 777 /dev/ffs-camtp -R")"); - - if (usb_ctx) - { - //camtp_set_usb_handle(camtp_context.get(), usb_ctx, camtp_context->usb_cfg.usb_max_packet_size); - camtp_context->usb_ctx = usb_ctx; - printf("function mode: %d\n", camtp_context->usb_cfg.usb_functionfs_mode); - if (camtp_context->usb_cfg.usb_functionfs_mode) - { - log_cls::log(LOG_LEVEL_ALL, "CAMTP Responder : FunctionFS Mode - entering handle_ffs_ep0\n"); - handle_ffs_ep0(usb_ctx); - } - else - { - log_cls::log(LOG_LEVEL_ALL, "CAMTP Responder : GadgetFS Mode - entering handle_ep0\n"); - handle_ep0(usb_ctx); - } - deinit_usb_camtp_gadget(usb_ctx); - } - else - { - PRINT_ERROR("USB Init failed !\n"); - retcode = -2; - loop_continue = 0; - } - - PRINT_MSG("CAMTP Responder : Disconnected"); - - } while (loop_continue); -} - - -// Function FS mode handler -int UsbDevice::handle_ffs_ep0(usb_gadget * ctx) -{ - struct timeval timeout; - int ret, nevents, i; - fd_set read_set; - struct usb_functionfs_event event; - int status; - - log_cls::log(LOG_LEVEL_ALL, "handle_ffs_ep0 : Entering...\n"); - timeout.tv_sec = 40; - timeout.tv_usec = 0; - - // status = init_eps(ctx,1); - while (!ctx->stop) - { - FD_ZERO(&read_set); - FD_SET(ctx->usb_device, &read_set); - - printf("select EP0 event ...\n"); - if(timeout.tv_sec) - { - ret = select(ctx->usb_device+1, &read_set, NULL, NULL, &timeout); - } - else - { - log_cls::log(LOG_LEVEL_ALL, "Select without timeout\n"); - ret = select(ctx->usb_device+1, &read_set, NULL, NULL, NULL); - } - - if(ctx->wait_connection && ret == 0 ) - continue; - - if( ret <= 0 ) - return ret; - - timeout.tv_sec = 0; - - ret = read(ctx->usb_device, &event, sizeof(event)); - if (ret < 0) - { - PRINT_ERROR("handle_ffs_ep0 : Read error %d (%m)", ret); - goto end; - } - - nevents = ret / sizeof(event); - - log_cls::log(LOG_LEVEL_ALL, "%d event(s)\n", nevents); - - printf("event type = %d\n", event.type); - for (i=0; iep_handles[EP_DESCRIPTOR_IN] <= 0) - { - status = init_eps(ctx,1); - } - else - status = 0; - - break; - case FUNCTIONFS_DISABLE: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS DISABLE\n"); - b_connected = false; - //printf(" USB DISCONNECTED\n"); - if(connect_call) - connect_call(b_connected); - //!< nick usb off - // Set timeout for a reconnection during the enumeration... - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - // Stop the main rx thread. - ctx->stop = 1; - if( !ctx->thread_not_started ) - { - pthread_join(ctx->thread, NULL); - ctx->thread_not_started = 1; - } - - for(int i = 0; i < sizeof(ctx->ep_handles) / sizeof(ctx->ep_handles[0]); ++i) - { - if(ctx->ep_handles[i] > 0) - close(ctx->ep_handles[i]); - ctx->ep_handles[i] = -1; - } -#ifdef EP_AUTO_SEND - if(bulk_sent_.get() && bulk_sent_->joinable()) - bulk_sent_->join(); - bulk_sent_.reset(); - if(bulk_read_.get() && bulk_read_->joinable()) - bulk_read_->join(); - bulk_read_.reset(); - if(int_sent_.get() && int_sent_->joinable()) - int_sent_->join(); - int_sent_.reset(); -#endif - - // But don't close the endpoints ! - ctx->stop = 0; - - break; - case FUNCTIONFS_SETUP: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS SETUP\n"); - handle_setup_request(ctx, &event.u.setup); - break; - case FUNCTIONFS_BIND: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS BIND\n"); - break; - case FUNCTIONFS_UNBIND: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS UNBIND\n"); - break; - case FUNCTIONFS_SUSPEND: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS SUSPEND\n"); - break; - case FUNCTIONFS_RESUME: - log_cls::log(LOG_LEVEL_ALL, "EP0 FFS RESUME\n"); - break; - } - } - } - - ctx->stop = 1; - -end: - log_cls::log(LOG_LEVEL_ALL, "handle_ffs_ep0 : Leaving... (ctx->stop=%d)\n",ctx->stop); - return 1; -} - - -// GadgetFS mode handler -int UsbDevice::handle_ep0(usb_gadget * ctx) -{ - struct timeval timeout; - int ret, nevents, i, cnt; - fd_set read_set; - struct usb_gadgetfs_event events[5]; - - log_cls::log(LOG_LEVEL_ALL, "handle_ep0 : Entering...\n"); - timeout.tv_sec = 4; - timeout.tv_usec = 0; - - while (!ctx->stop) - { - FD_ZERO(&read_set); - FD_SET(ctx->usb_device, &read_set); - - if(timeout.tv_sec) - { - ret = select(ctx->usb_device+1, &read_set, NULL, NULL, &timeout); - } - else - { - log_cls::log(LOG_LEVEL_ALL, "handle_ep0 : Select without timeout\n"); - ret = select(ctx->usb_device+1, &read_set, NULL, NULL, NULL); - } - - if(ctx->wait_connection && ret == 0 ) - continue; - - if( ret <= 0 ) - return ret; - - timeout.tv_sec = 0; - - ret = read(ctx->usb_device, &events, sizeof(events)); - - if (ret < 0) - { - PRINT_ERROR("handle_ep0 : Read error %d (%m)", errno); - goto end; - } - - nevents = ret / sizeof(events[0]); - - log_cls::log(LOG_LEVEL_ALL, "handle_ep0 : %d event(s)\n", nevents); - - for (i=0; istop = 1; - if( !ctx->thread_not_started ) - { - pthread_cancel(ctx->thread); - pthread_join(ctx->thread, NULL); - ctx->thread_not_started = 1; - } - break; - - case GADGETFS_SETUP: - log_cls::log(LOG_LEVEL_ALL, "handle_ep0 : EP0 SETUP event\n"); - handle_setup_request(ctx, &events[i].u.setup); - break; - - case GADGETFS_NOP: - log_cls::log(LOG_LEVEL_ALL, "handle_ep0 : EP0 NOP event\n"); - break; - - case GADGETFS_SUSPEND: - log_cls::log(LOG_LEVEL_ALL, "handle_ep0 : EP0 SUSPEND event\n"); - - break; - - default: - log_cls::log(LOG_LEVEL_ALL, "handle_ep0 : EP0 unknown event : %d\n",events[i].type); - break; - } - } - } - - ctx->stop = 1; - -end: - log_cls::log(LOG_LEVEL_ALL, "handle_ep0 : Leaving (ctx->stop=%d)...\n",ctx->stop); - - return 1; -} - - -void UsbDevice::handle_setup_request(usb_gadget * ctx, struct usb_ctrlrequest* setup) -{ - int status,cnt; - uint8_t buffer[512]; - camtp_device_status dstatus; - - log_cls::log(LOG_LEVEL_ALL, "Setup request 0x%02X\n", setup->bRequest); - - printf("Request: %02X\n", setup->bRequest); - if(ctrl_handler && ctrl_handler(ctx->usb_device, setup, buffer)) - return; - - printf("service not handle: %x\n", setup->bRequest); - switch (setup->bRequest) - { - case USB_REQ_GET_DESCRIPTOR: - if (setup->bRequestType != USB_DIR_IN) - goto stall; - - switch (setup->wValue >> 8) - { - case USB_DT_STRING: - log_cls::log(LOG_LEVEL_ALL, "Get string id #%d (max length %d)\n", setup->wValue & 0xff, - setup->wLength); - status = usb_gadget_get_string (&strings, setup->wValue & 0xff, buffer); - // Error - if (status < 0) - { - PRINT_ERROR("handle_setup_request : String id #%d (max length %d) not found !\n",setup->wValue & 0xff, setup->wLength); - break; - } - else - { - log_cls::log(LOG_LEVEL_ALL, "Found %d bytes\n", status); - PRINT_DEBUG_BUF(buffer, status); - } - - if ( write (ctx->usb_device, buffer, status) < 0 ) - { - PRINT_ERROR("handle_setup_request - USB_REQ_GET_DESCRIPTOR : usb device write error !"); - break; - } - - return; - break; - default: - log_cls::log(LOG_LEVEL_ALL, "Cannot return descriptor %d\n", (setup->wValue >> 8)); - break; - } - break; - - case USB_REQ_SET_CONFIGURATION: - if (setup->bRequestType != USB_DIR_OUT) - { - log_cls::log(LOG_LEVEL_ALL, "Bad dir\n"); - goto stall; - } - - switch (setup->wValue) - { - case CONFIG_VALUE: - log_cls::log(LOG_LEVEL_ALL, "Set config value\n"); - - if (ctx->ep_handles[EP_DESCRIPTOR_IN] <= 0) - { - status = init_eps(ctx,0); - } - else - status = 0; - - break; - case 0: - log_cls::log(LOG_LEVEL_ALL, "Disable threads\n"); - ctx->stop = 1; - break; - - default: - log_cls::log(LOG_LEVEL_ALL, "Unhandled configuration value %d\n", setup->wValue); - break; - } - - // Just ACK - status = read (ctx->usb_device, &status, 0); - return; - break; - - case USB_REQ_GET_INTERFACE: - log_cls::log(LOG_LEVEL_ALL, "GET_INTERFACE\n"); - buffer[0] = 0; - - if ( write (ctx->usb_device, buffer, 1) < 0 ) - { - PRINT_ERROR("handle_setup_request - USB_REQ_GET_INTERFACE : usb device write error !\n"); - break; - } - - return; - break; - - case USB_REQ_SET_INTERFACE: - log_cls::log(LOG_LEVEL_ALL, "SET_INTERFACE\n"); - ioctl (ctx->ep_handles[EP_DESCRIPTOR_IN], GADGETFS_CLEAR_HALT); - ioctl (ctx->ep_handles[EP_DESCRIPTOR_OUT], GADGETFS_CLEAR_HALT); - ioctl (ctx->ep_handles[EP_DESCRIPTOR_INT_IN], GADGETFS_CLEAR_HALT); - // ACK - status = read (ctx->usb_device, &status, 0); - return; - break; - - } - -stall: - log_cls::log(LOG_LEVEL_ALL, "Stalled\n"); - // Error - if (setup->bRequestType & USB_DIR_IN) - { - if ( read (ctx->usb_device, &status, 0) < 0 ) - { - log_cls::log(LOG_LEVEL_ALL, "handle_setup_request - stall : usb device read error !\n"); - } - } - else - { - if ( write (ctx->usb_device, &status, 0) < 0 ) - { - log_cls::log(LOG_LEVEL_ALL, "handle_setup_request - stall : usb device write error !\n"); - } - } -} - -int UsbDevice::init_ep(usb_gadget * ctx,int index,int ffs_mode, bool open_ep) -{ - int fd,ret; - void * descriptor_ptr; - int descriptor_size; - - log_cls::log(LOG_LEVEL_ALL, "Init end point %s (%d)\n",ctx->ep_path[index],index); - if(open_ep) - { - fd = open(ctx->ep_path[index], O_RDWR); - log_cls::log(LOG_LEVEL_ALL, "open_usb_ep(%s) = %d\n", ctx->ep_path[index], fd); - if ( fd <= 0 ) - { - PRINT_ERROR("init_ep : Endpoint %s (%d) init failed ! : Can't open the endpoint ! (error %d - %m)",ctx->ep_path[index],index,fd); - goto init_ep_error; - } - - ctx->ep_handles[index] = fd; - } - - ctx->ep_config[index]->head = 1; - - descriptor_size = 0; - - if( ctx->usb_ffs_config ) - { -#if defined(CONFIG_USB_SS_SUPPORT) - descriptor_ptr = (void *)&ctx->usb_ffs_config->ep_desc_ss; - descriptor_size = sizeof(ep_cfg_descriptor); -#elif defined(CONFIG_USB_HS_SUPPORT) - descriptor_ptr = (void *)&ctx->usb_ffs_config->ep_desc_hs; - descriptor_size = sizeof(struct usb_endpoint_descriptor_no_audio); -#elif defined(CONFIG_USB_FS_SUPPORT) - descriptor_ptr = (void *)&ctx->usb_ffs_config->ep_desc_fs; - descriptor_size = sizeof(struct usb_endpoint_descriptor_no_audio); -#else - -#error Configuration Error ! At least one USB mode support must be enabled ! (CONFIG_USB_FS_SUPPORT/CONFIG_USB_HS_SUPPORT/CONFIG_USB_SS_SUPPORT) - -#endif - } - else - { -#if defined(CONFIG_USB_SS_SUPPORT) - descriptor_ptr = (void *)&ctx->usb_config->ep_desc_ss; - descriptor_size = sizeof(ep_cfg_descriptor); -#elif defined(CONFIG_USB_HS_SUPPORT) - descriptor_ptr = (void *)&ctx->usb_config->ep_desc_hs; - descriptor_size = sizeof(struct usb_endpoint_descriptor_no_audio); -#elif defined(CONFIG_USB_FS_SUPPORT) - descriptor_ptr = (void *)&ctx->usb_config->ep_desc_fs; - descriptor_size = sizeof(struct usb_endpoint_descriptor_no_audio); -#else - -#error Configuration Error ! At least one USB mode support must be enabled ! (CONFIG_USB_FS_SUPPORT/CONFIG_USB_HS_SUPPORT/CONFIG_USB_SS_SUPPORT) - -#endif - } - -#if defined(CONFIG_USB_SS_SUPPORT) - switch(index) - { - case EP_DESCRIPTOR_IN: - memcpy(&ctx->ep_config[index]->ep_desc[0], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_in,descriptor_size); - memcpy(&ctx->ep_config[index]->ep_desc[1], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_in,descriptor_size); - break; - case EP_DESCRIPTOR_OUT: - memcpy(&ctx->ep_config[index]->ep_desc[0], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_out,descriptor_size); - memcpy(&ctx->ep_config[index]->ep_desc[1], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_out,descriptor_size); - break; - case EP_DESCRIPTOR_INT_IN: - memcpy(&ctx->ep_config[index]->ep_desc[0], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_int_in,descriptor_size); - memcpy(&ctx->ep_config[index]->ep_desc[1], &((SSEndPointsDesc*)descriptor_ptr)->ep_desc_int_in,descriptor_size); - break; - } -#else - switch(index) - { - case EP_DESCRIPTOR_IN: - memcpy(&ctx->ep_config[index]->ep_desc[0], &((EndPointsDesc*)descriptor_ptr)->ep_desc_in,descriptor_size); - memcpy(&ctx->ep_config[index]->ep_desc[1], &((EndPointsDesc*)descriptor_ptr)->ep_desc_in,descriptor_size); - break; - case EP_DESCRIPTOR_OUT: - memcpy(&ctx->ep_config[index]->ep_desc[0], &((EndPointsDesc*)descriptor_ptr)->ep_desc_out,descriptor_size); - memcpy(&ctx->ep_config[index]->ep_desc[1], &((EndPointsDesc*)descriptor_ptr)->ep_desc_out,descriptor_size); - break; - case EP_DESCRIPTOR_INT_IN: - memcpy(&ctx->ep_config[index]->ep_desc[0], &((EndPointsDesc*)descriptor_ptr)->ep_desc_int_in,descriptor_size); - memcpy(&ctx->ep_config[index]->ep_desc[1], &((EndPointsDesc*)descriptor_ptr)->ep_desc_int_in,descriptor_size); - break; - } -#endif - - log_cls::log(LOG_LEVEL_ALL, "init_ep (%d):\n",index); - PRINT_DEBUG_BUF(ctx->ep_config[index], sizeof(ep_cfg)); - - if(!ffs_mode) - { - if(open_ep) - { - ret = write(fd, ctx->ep_config[index], sizeof(ep_cfg)); - - if (ret != sizeof(ep_cfg)) - { - PRINT_ERROR("init_ep : Endpoint %s (%d) init failed ! : Write Error %d - %m",ctx->ep_path[index], index, ret); - goto init_ep_error; - } - } - } - else - { - log_cls::log(LOG_LEVEL_ALL, "init_ep (%d): FunctionFS Mode - Don't write the endpoint descriptor.\n",index); - } - - return fd; - -init_ep_error: - return 0; -} - -#include -bool now(struct timeval* tv) -{ - struct timezone tz = { 0 }; - bool ok = gettimeofday(tv, &tz) == 0; - - // tv->tv_sec -= 60 * tz.tz_minuteswest; - - return ok; -} -std::string time_now(void) // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false -{ - struct timeval tv = { 0 }; - - if (!now(&tv)) - return ""; - - char buf[40] = { 0 }; - time_t t = tv.tv_sec; - struct tm* l = localtime(&t); - static int cnt = 0; - - sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday - , l->tm_hour, l->tm_min, l->tm_sec, tv.tv_usec); - - return buf; -} -std::string send_for_int(void) -{ - return "abcdefghijklmnopqrstuvwxyz/[]{}|+=ABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%^&*()_+-=~<>;ENDOFINTERRUPTCONTENT!!!!"; -} -static void send_timer_tick(UsbDevice *dev, int type) -{ - std::string pre(type == EP_DESCRIPTOR_INT_IN ? "[Intr] " : "[Bulk] "); - int (UsbDevice::*sendf)(void*, int, int*) = type == EP_DESCRIPTOR_INT_IN ? &UsbDevice::write_int : &UsbDevice::write_bulk; - std::string (*content)(void) = type == EP_DESCRIPTOR_INT_IN ? send_for_int : time_now; - int err = 0, out = 0; - - printf("timer tick thread(%p - %s) running ...\n", pthread_self(), pre.c_str()); - while(1) - { - std::string cur(pre + content()); - printf("now: %s\n", cur.c_str()); - out = (dev->*sendf)(&cur[0], cur.length(), &err); - if(out != cur.length()) - printf("\tPartial data sent: %d/%d\n", out, cur.length()); - if(err == EBADF || err == ESHUTDOWN) - break; - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - printf("timer tick thread(%p - %s) exited.\n", pthread_self(), pre.c_str()); -} -static void read_bulk_thread(UsbDevice *dev) -{ - char buf[513] = {0}; - - printf("read_bulk_thread(%p) running ...\n", pthread_self()); - while(1) - { - int err = 0, - l = dev->read_bulk(buf, sizeof(buf) - 1, &err, false); - if(err == EBADF || err == ESHUTDOWN) - break; - buf[l] = 0; - printf("--Recived: %s\n", buf); - } - printf("read_bulk_thread(%p) exited.\n", pthread_self()); -} - -int UsbDevice::init_eps(usb_gadget * ctx, int ffs_mode, bool open_ep) -{ - if( !init_ep(ctx, EP_DESCRIPTOR_IN, ffs_mode, open_ep) && open_ep ) - goto init_eps_error; - - if( !init_ep(ctx, EP_DESCRIPTOR_OUT, ffs_mode, open_ep) && open_ep ) - goto init_eps_error; - - if( !init_ep(ctx, EP_DESCRIPTOR_INT_IN, ffs_mode, open_ep) && open_ep ) - goto init_eps_error; - -#ifdef EP_AUTO_SEND - bulk_sent_.reset(new std::thread(&send_timer_tick, this, EP_DESCRIPTOR_IN)); - bulk_read_.reset(new std::thread(&read_bulk_thread, this)); - int_sent_.reset(new std::thread(&send_timer_tick, this, EP_DESCRIPTOR_INT_IN)); -#endif - - return 0; - -init_eps_error: - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -#ifdef ASYNC_EP -static std::string get_value(const char* key) -{ - if(strcmp(key, "dev-sn") == 0) - return "20230330001A"; - - if(strcmp(key, "fwmver") == 0) - return "2023001"; - - return "not-supported"; -} -void dump_buf(uint8_t *data, int len) -{ - uint32_t addr = 0; - std::string asc(""); - for(int i = 0; i < len; ++i) - { - if((i % 16) == 0) - { - printf(" %s\n0x%08x ", asc.c_str(), addr); - addr += 16; - asc = ""; - } - else if((i % 8) == 0) - { - printf(" "); - } - - uint8_t v = data[i]; - printf("%02X ", v); - if(v >= 0x20 && v < 0x7f) - asc.append(1, v); - else - asc += "."; - } - if(asc.length()) - { - std::string pad(" "); - if(asc.length() <= 8) - pad.erase((16 - asc.length()) * 3 + 2); - else if(asc.length() < 16) - pad.erase((16 - asc.length()) * 3); - else - pad = ""; - printf("%s %s", pad.c_str(), asc.c_str()); - } - printf("\n"); - -} - -dyn_mem_ptr UsbDevice::unhandled_ep0(struct usb_functionfs_event* pev) -{ - return nullptr; -} -dyn_mem_ptr UsbDevice::handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) -{ - dyn_mem_ptr reply = nullptr; - LPPACK_BASE pk = nullptr; - size_t base_head_size = sizeof(PACK_BASE); - - if(pack->size != base_head_size) - { - log_cls::log(LOG_LEVEL_ALL, "Unknown Packet with %d bytes:\n", *used); - dump_buf((uint8_t*)pack, *used); - reply = dyn_mem::memory(base_head_size); - LPPACK_BASE p = (LPPACK_BASE)reply->ptr(); - BASE_PACKET_REPLY(*p, PACK_CMD_INVALID, pack->pack_id, pack->cmd); - reply->set_len(base_head_size); - - return reply; - } - - switch(pack->cmd) - { - case PACK_CMD_SYNC: - *used = sizeof(PACK_BASE); - reply = dyn_mem::memory(base_head_size); - pk = (LPPACK_BASE)reply->ptr(); - BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, 0); - reply->set_len(base_head_size); - break; - case PACK_CMD_SETTING_GET_CUR: - if(*used < base_head_size + pack->payload_len) - *used = 0; - else - { - std::string val(get_value(pack->payload)); - LPCFGVAL cfg = nullptr; - - reply = dyn_mem::memory(base_head_size + sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1); - pk = (LPPACK_BASE)reply->ptr(); - BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, 0); - cfg = (LPCFGVAL)pk->payload; - cfg->val_size = val.length(); - cfg->val_off = 0; - cfg->name_off = val.length() + 1; - pk->payload_len = sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1; - strcpy(cfg->data, val.c_str()); - strcpy(cfg->data + cfg->name_off, pack->payload); - reply->set_len(base_head_size + pk->payload_len); - *used = base_head_size + pack->payload_len; - } - break; - case PACK_CMD_FILE_WRITE_REQ: - if(*used < pack->payload_len + pack->size) - { - *used = 0; - } - else - { - LPTXFILE pfi = (LPTXFILE)pack->payload; - std::string path(pfi->path); - int err = 0; - file_saver *saver = new file_saver(); - - err = saver->open(path.c_str(), pfi->size); - reply = dyn_mem::memory(base_head_size); - reply->set_len(base_head_size); - BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); - *used = base_head_size + pack->payload_len; - if(err) - { - saver->release(); - saver = nullptr; - } - else - { - saver->set_packet_param(pack->cmd, pack->pack_id); - } - log_cls::log(LOG_LEVEL_DEBUG, "receive file (%u bytes): %s = %d\n", pfi->size, path.c_str(), err); - *required = dynamic_cast(saver); - } - break; - case PACK_CMD_FILE_READ_REQ: - if(*used < pack->payload_len + pack->size) - { - *used = 0; - } - else - { - LPTXFILE pfi = (LPTXFILE)pack->payload; - std::string path(pfi->path); - int err = 0; - file_reader *reader = new file_reader(); - - err = reader->open(path.c_str()); - reply = dyn_mem::memory(base_head_size + sizeof(TXFILE)); - reply->set_len(base_head_size + sizeof(TXFILE)); - BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); - *used = base_head_size + pack->payload_len; - log_cls::log(LOG_LEVEL_DEBUG, "To send file '%s' with %u bytes = %d\n", path.c_str(), reader->get_rest(), err); - if(err) - { - reader->release(); - reader = nullptr; - } - else - { - ((LPPACK_BASE)reply->ptr())->payload_len = sizeof(TXFILE); - ((LPTXFILE)((LPPACK_BASE)reply->ptr())->payload)->size = reader->get_rest(); - reader->set_packet_param(pack->cmd, pack->pack_id); - } - *required = dynamic_cast(reader); - } - break; - } - - return reply; -} -void UsbDevice::do_system_command(const char* cmd) -{ - log_cls::log(LOG_LEVEL_ALL, "invoking system command: %s ...\n", cmd); - get_system_output(cmd); - log_cls::log(LOG_LEVEL_ALL, "invoked system command: %s.\n", cmd); -} -#endif diff --git a/device/gxx-linux/testusb/usb-rk3399/src/usbstring.cpp b/device/gxx-linux/testusb/usb-rk3399/src/usbstring.cpp deleted file mode 100644 index 9159250..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/src/usbstring.cpp +++ /dev/null @@ -1,349 +0,0 @@ -/* - * uMTP Responder - * Copyright (c) 2018 - 2020 Viveris Technologies - * - * uMTP Responder 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.0 of the License, or (at your option) any later version. - * - * uMTP Responder 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 version 3 for more details. - * - * You should have received a copy of the GNU General Public License - * along with uMTP Responder; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - - /** - * @file usbstring.c - * @brief USB Strings - * @author Jean-François DEL NERO - */ - -/* - * - * Note : This source file is based on the Linux kernel usbstring.c - * with the following Licence/copyright : - * - */ - -/* - * Copyright (C) 2003 David Brownell - * - * This program 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. - */ - -#include "buildconf.h" - -#include - -#include -#include -#include - -#include -#include - -#include "usbstring.h" - -/* From usbstring.[ch] */ - -static inline void put_unaligned_le16(uint16_t val, uint16_t *cp) -{ - uint8_t *p = (uint8_t *)cp; - - *p++ = (uint8_t) val; - *p++ = (uint8_t) (val >> 8); -} - -static int utf8_to_utf16le(const char *s, uint16_t *cp, unsigned len) -{ - int count = 0; - uint8_t c; - uint16_t uchar; - - /* this insists on correct encodings, though not minimal ones. - * BUT it currently rejects legit 4-byte UTF-8 code points, - * which need surrogate pairs. (Unicode 3.1 can use them.) - */ - while (len != 0 && (c = (uint8_t) *s++) != 0) { - if (c & 0x80) { - // 2-byte sequence: - // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx - if ((c & 0xe0) == 0xc0) { - uchar = (c & 0x1f) << 6; - - c = (uint8_t) *s++; - if ((c & 0xc0) != 0xc0) - goto fail; - c &= 0x3f; - uchar |= c; - - // 3-byte sequence (most CJKV characters): - // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx - } else if ((c & 0xf0) == 0xe0) { - uchar = (c & 0x0f) << 12; - - c = (uint8_t) *s++; - if ((c & 0xc0) != 0xc0) - goto fail; - c &= 0x3f; - uchar |= c << 6; - - c = (uint8_t) *s++; - if ((c & 0xc0) != 0xc0) - goto fail; - c &= 0x3f; - uchar |= c; - - /* no bogus surrogates */ - if (0xd800 <= uchar && uchar <= 0xdfff) - goto fail; - - // 4-byte sequence (surrogate pairs, currently rare): - // 11101110wwwwzzzzyy + 110111yyyyxxxxxx - // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx - // (uuuuu = wwww + 1) - // FIXME accept the surrogate code points (only) - - } else - goto fail; - } else - uchar = c; - put_unaligned_le16 (uchar, cp++); - count++; - len--; - } - return count; -fail: - return -1; -} - -int usb_gadget_get_string (struct usb_gadget_strings *table, int id, uint8_t *buf) -{ - struct usb_string *s; - int len; - - /* descriptor 0 has the language id */ - if (id == 0) { - buf [0] = 4; - buf [1] = USB_DT_STRING; - buf [2] = (uint8_t) table->language; - buf [3] = (uint8_t) (table->language >> 8); - return 4; - } - for (s = table->strings; s && s->str; s++) - if (s->id == id) - break; - - /* unrecognized: stall. */ - if (!s || !s->str) - return -EINVAL; - - /* string descriptors have length, tag, then UTF16-LE text */ - len = strlen (s->str); - if (len > 126) - len = 126; - memset (buf + 2, 0, 2 * len); /* zero all the bytes */ - len = utf8_to_utf16le(s->str, (uint16_t *)&buf[2], len); - if (len < 0) - return -EINVAL; - buf [0] = (len + 1) * 2; - buf [1] = USB_DT_STRING; - return buf [0]; -} - -int utf8_encode(char *out, uint32_t unicode) -{ - if (unicode <= 0x7F) - { - // ASCII - *out++ = (char) unicode; - *out++ = 0; - return 1; - } - else if (unicode <= 0x07FF) - { - // 2-bytes unicode - *out++ = (char) (((unicode >> 6) & 0x1F) | 0xC0); - *out++ = (char) (((unicode >> 0) & 0x3F) | 0x80); - *out++ = 0; - return 2; - } - else if (unicode <= 0xFFFF) - { - // 3-bytes unicode - *out++ = (char) (((unicode >> 12) & 0x0F) | 0xE0); - *out++ = (char) (((unicode >> 6) & 0x3F) | 0x80); - *out++ = (char) (((unicode >> 0) & 0x3F) | 0x80); - *out++ = 0; - return 3; - } - else if (unicode <= 0x10FFFF) - { - // 4-bytes unicode - *out++ = (char) (((unicode >> 18) & 0x07) | 0xF0); - *out++ = (char) (((unicode >> 12) & 0x3F) | 0x80); - *out++ = (char) (((unicode >> 6) & 0x3F) | 0x80); - *out++ = (char) (((unicode >> 0) & 0x3F) | 0x80); - *out++ = 0; - - return 4; - } - else - { - // error - return 0; - } -} - -int unicode2charstring(char * str, uint16_t * unicodestr, int maxstrsize) -{ - int i,j,ret; - int chunksize; - char tmpstr[8]; - - ret = 0; - i = 0; - while( *unicodestr ) - { - chunksize = utf8_encode((char*)&tmpstr, *unicodestr++); - - if(!chunksize) - { // Error -> default character - tmpstr[0] = '?'; - tmpstr[1] = 0; - chunksize = 1; - } - - if( (i + chunksize) < maxstrsize ) - { - for( j = 0 ; j < chunksize ; j++ ) - { - str[i] = tmpstr[j]; - i++; - } - } - else - { - str[ maxstrsize - 1 ] = 0; - ret = 1; - break; - } - }; - - if( i < maxstrsize ) - str[i] = 0; - - return ret; -} - -static int utf8_size(char c) -{ - int count = 0; - - while (c & 0x80) - { - c = c << 1; - count++; - } - - if(!count) - count = 1; - - return count; -} - -uint16_t utf2unicode(const unsigned char* pInput, int * ofs) -{ - uint8_t b1, b2, b3; - int utfsize; - uint16_t unicode_out; - - *ofs = 0; - - utfsize = utf8_size(*pInput); - - switch ( utfsize ) - { - case 1: - unicode_out = *pInput; - *ofs = 1; - return unicode_out; - break; - - case 2: - b1 = *pInput++; - b2 = *pInput++; - - if ( (b2 & 0xC0) != 0x80 ) - return 0x0000; - - unicode_out = ( ( (b1 & 0x1F) << 6 ) | (b2 & 0x3F) ) & 0xFF; - unicode_out |= (uint16_t)((b1 & 0x1F) >> 2) << 8; - *ofs = 2; - return unicode_out; - break; - - case 3: - b1 = *pInput++; - b2 = *pInput++; - b3 = *pInput++; - - if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) ) - return 0x0000; - - unicode_out = (uint16_t)( ((b2 & 0x3F) << 6) | (b3 & 0x3F) ) & 0x00FF; - unicode_out |= (uint16_t)( ((b1 & 0xF) << 4) | ((b2 & 0x3F) >> 2 ) ) << 8; - - *ofs = 3; - - return unicode_out; - break; - - default: - *ofs = 0; - - return 0x0000; - break; - } - - return 0x0000; -} - -int char2unicodestring(char * unicodestr, int index, int maxsize, char * str, int unicodestrsize) -{ - uint16_t unicode; - int ofs, len, start; - - start = index; - len = 0; - ofs = 0; - do{ - unicode = utf2unicode((unsigned char*)str, &ofs); - str = str + ofs; - if(index + 2 >= maxsize) - return -1; - unicodestr[index++] = unicode & 0xFF; - unicodestr[index++] = (unicode >> 8) & 0xFF; - len++; - }while(unicode && ofs && index < unicodestrsize*2); - - if( len >= unicodestrsize) - { - if(start + ((unicodestrsize*2)-2) >= maxsize) - return -1; - - unicodestr[start + ((unicodestrsize*2)-2)] = 0x00; - unicodestr[start + ((unicodestrsize*2)-1)] = 0x00; - len = unicodestrsize; - } - - return len; -} diff --git a/device/gxx-linux/testusb/usb-rk3399/usbimageprocqueue.h b/device/gxx-linux/testusb/usb-rk3399/usbimageprocqueue.h deleted file mode 100644 index f6ed6bf..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/usbimageprocqueue.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once -#include -#include "imgproc.h" -#include "mutex" -#include "itransmit.h" -#include "inotify.h" -#include "ireceive.h" -#include "BlockingQueue.h" - -class UsbImageProcQueue -{ -public: - UsbImageProcQueue(NotifyPtr notify) - { - this->notify = notify; - } - - void push(MemoryPtr image,bool containsimg) - { - std::lock_guard lck(mx); - HGIntInfo info; - if(containsimg) - { - printf("UsbImageProcQueue::push\n"); - images.push(image); - //images.Put(image); - info.From = IMG; - info.Code = image->size(); - } - else - { - info = *((HGIntInfo*)image->data()); - } - if(notify) - notify->notify(&info, sizeof(info)); - } - - - MemoryPtr front() - { - std::lock_guard lck(mx); - - auto front = images.front(); - return front; - //return images.Front(); - } - - MemoryPtr pop() - { - std::lock_guard lck(mx); - if(images.size()>0) - { - printf("UsbImageProcQueue::pop\n"); - auto front = images.front(); - images.pop(); - //auto front=images.Take(); - return front; - } - return MemoryPtr(); - } - - bool empty() - { - std::lock_guard lck(mx); - return images.empty(); - //return images.Size()>0; - } - - int size() - { - std::lock_guard lck(mx); - return images.size(); - //return images.Size(); - } - - int front_datasize() - { - std::lock_guard lck(mx); - if(images.size()<1) - return 0; - auto img=images.front(); - return images.empty() ? 0 : images.front()->size(); - //return (images.Size()>0) ? 0 : images.Front()->size(); - } - - - void clear() - { - std::lock_guard lck(mx); - while(images.size()>0) - images.pop(); - } - -private: - std::queue images; - //BlockingQueue images; - NotifyPtr notify; - std::mutex mx; -}; \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/usbnotify.cpp b/device/gxx-linux/testusb/usb-rk3399/usbnotify.cpp deleted file mode 100644 index caf1095..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/usbnotify.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "usbnotify.h" -#include "usbdevice.h" -#include "StopWatch.h" -#include -#include - -UsbNotify::UsbNotify(std::shared_ptr usb) -: brun(true) -{ - this->usb= usb; - runThread.reset(new ThreadEx(&UsbNotify::run_notify, this)); -} - -UsbNotify::~UsbNotify() -{ - brun = false; - ae.notify_all(); -} - -void UsbNotify::notify(void* data, int size) -{ - if(!usb || !usb->is_connected()) - return; - - std::lock_guard lck(mx); - // StopWatch sw; - // while (msgs.empty() && sw.elapsed_ms() < 100); - - // if(!msgs.empty()) - // msgs = std::queue>(); - - std::vector msg(size); - memcpy(&msg[0],data,size); - msgs.push(msg); - //msgs.push(std::vector((unsigned char*)data, (unsigned char*)data + size)); - ae.notify_all(); -} - -void UsbNotify::clear() -{ - usb->abort_int(); - std::lock_guard lck(mx); - msgs = std::queue>(); -} - -void UsbNotify::run_notify() -{ - unsigned char buff[64]; - while(brun) - { - if (ae.wait(300000) && brun) - { - for(;;) - { - { - std::lock_guard lck(mx); - if(msgs.empty()) - break; - auto &data = msgs.front(); - memset(buff,0,sizeof(buff)); - std::copy(data.begin(), data.end(), buff); - } - - if (usb && usb->is_connected()) - usb->write_int(buff, sizeof(buff)); - - { - std::lock_guard lck(mx); - if(msgs.size()>0) - msgs.pop(); - } - } - } - } -} \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/usbnotify.h b/device/gxx-linux/testusb/usb-rk3399/usbnotify.h deleted file mode 100644 index 78c6035..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/usbnotify.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "inotify.h" -#include "autoevent.hpp" -#include -#include -#include -#include - -class UsbDevice; - -class UsbNotify : public INotify -{ -public: - UsbNotify(std::shared_ptr usb); - virtual ~UsbNotify(); - virtual void notify(void* data, int size); - virtual void clear(); - -private: - void run_notify(); - - std::shared_ptr runThread; - AutoEvent ae; - std::mutex mx; - std::queue> msgs; - std::shared_ptr usb; - volatile bool brun; -}; \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/usbreceive.cpp b/device/gxx-linux/testusb/usb-rk3399/usbreceive.cpp deleted file mode 100644 index 4c453b0..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/usbreceive.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "usbreceive.h" -#include "memoryex.h" -#include "applog.h" -#include -#include "usbdevice.h" - -static std::string loggername = "UsbReceive"; - -UsbReceive::UsbReceive(std::shared_ptr t_usb) -{ - LOG_INIT(); - this->usb=t_usb; -} - - -UsbReceive::~UsbReceive() -{ - cannel(); -} - -int UsbReceive::read(MemoryPtr& memroy) -{ - int nread=0; - LOG_TRACE("rx start in"); - if (is_reading()) - return nread; - - runthread.reset(new ThreadEx([this, memroy]() { - LOG_TRACE("rx starting"); - if (usb && usb->is_connected()) - usb->read_bulk(memroy->data(), memroy->size()); - - LOG_TRACE("rx started"); - })); - return nread; -} - -int UsbReceive::read_bulk(void* data,unsigned int length) -{ - printf("(%p)perform read_bulk in UsbReceive object...\n", pthread_self()); - int nread=0; - if(usb.get()&&usb->is_connected()) - { - if(data != nullptr && length >0) - nread = usb->read_bulk(data,length); - else - LOG_TRACE("read_bulk uncorrect data ptr or length"); - } - printf("(%p)read_bulk in UsbReceive object OVER.\n", pthread_self()); - - return nread; -} - -bool UsbReceive::is_reading() -{ - return runthread&&runthread->is_runing(); -} - -void UsbReceive::cannel() -{ - if(runthread.get()) - runthread->cannel(); -} \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/usbreceive.h b/device/gxx-linux/testusb/usb-rk3399/usbreceive.h deleted file mode 100644 index 0dc014e..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/usbreceive.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include "ireceive.h" - -class UsbDevice; -class ThreadEx; - -class UsbReceive :public IReceive -{ -public: - UsbReceive(std::shared_ptr t_usb); - virtual ~UsbReceive(); - - virtual int read(MemoryPtr &memroy); - virtual int read_bulk(void* data,unsigned int length); - virtual bool is_reading(); - virtual void cannel(); - -private: - std::shared_ptr usb; - std::shared_ptr runthread; -}; diff --git a/device/gxx-linux/testusb/usb-rk3399/usbservice.cpp b/device/gxx-linux/testusb/usb-rk3399/usbservice.cpp deleted file mode 100644 index 7496ecf..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/usbservice.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#include "usbservice.h" -#include -#include -#include -#include -#include "stringex.hpp" -#include -#include -#include "usbdevice.h" -#include "regsaccess.h" -#include "usbtransmit.h" -#include "usbreceive.h" -#include "usbnotify.h" -#include "applog.h" -#include "../../scanner/scannerregs.h" - -static const std::string loggername = "UsbService"; - -typedef struct -{ - int Command; - int Data; - int Length; -} USBCB; - -#define USB_REQ_GET_FPGA_REGS 0x40 -#define USB_REQ_SET_FPGA_REGS 0x41 -#define USB_REQ_GET_MOTOR_REGS 0x42 -#define USB_REQ_SET_MOTOR_REGS 0x43 - -#define USB_REQ_ACCES_DEV_LOG 0x50 - -#define USB_REQ_GET_DEV_STATUS 0x60 -#define USB_REQ_GET_DEV_CONFIGURATION 0x61 -#define USB_REQ_SET_DEV_CONFIGURATION 0x62 -#define USB_REQ_GET_DEV_REGS 0x63 -#define USB_REQ_SET_DEV_REGS 0x64 -#define USB_REQ_GET_DEV_LOG 0x65 -#define USB_REQ_SET_DEV_LOG 0x66 - -static bool read_regs(unsigned int *regs, int regindex, int creg, std::shared_ptr ®sacess) -{ - printf("read_regs enter ...\n"); - int index; - for (int i = 0; i < creg; i++) - { - index = regindex + i; - if (!regsacess->read(index, *(regs + i))) - { - LOG_ERROR(string_format("read error %d=%08x\n", index, regs[i])); - return false; - } - LOG_TRACE(string_format("read %d=%08x\n", index, regs[i])); - } - printf("read_regs exit ...\n"); - - return true; -} - -static bool write_regs(unsigned int *regs, int regindex, int creg, std::shared_ptr ®sacess) -{ - printf("write_regs enter ...\n"); - int index; - bool ret = true; - for (int i = 0; i < creg; i++) - { - index = regindex + i; - if (!regsacess->write(index, *(regs + i))) - { - LOG_ERROR(string_format("wirte error %d=%08x\n", index, regs[i])); - ret = false; - break; - } - LOG_TRACE(string_format("wirte %d=%08x\n", index, regs[i])); - } - printf("write_regs exit.\n"); - return ret; -} - -UsbService::UsbService(std::shared_ptr fgparegs, std::shared_ptr motorregs, std::shared_ptr scannerregs) : scanner_(nullptr) -{ - LOG_INIT(); - this->fgparegs = fgparegs; - this->motorregs = motorregs; - this->devregs = scannerregs.get(); - auto ctrl_handle = [&](int fd, struct usb_ctrlrequest *setup, unsigned char *buffer) -> bool - { - printf("req = %x, type = %x, ind = %x, len = %x, val = %x\n", setup->bRequest, setup->bRequestType, setup->wIndex, setup->wLength, setup->wValue); - if (!(setup->bRequestType & USB_TYPE_VENDOR) || (setup->bRequestType & USB_RECIP_MASK) != USB_RECIP_DEVICE) - return false; - - static std::string logstring; - unsigned int *regs = (unsigned int *)buffer; - int creg = 0; - if (!(setup->wLength % 4)) - creg = setup->wLength / 4; - - int regindex = setup->wValue; - - switch (setup->bRequest) - { - case USB_REQ_GET_FPGA_REGS: - if ((setup->bRequestType & USB_DIR_IN) && creg && this->fgparegs) - { - if (!read_regs(regs, regindex, creg, this->fgparegs)) - return false; - ::write(fd, buffer, setup->wLength); - return true; - } - break; - case USB_REQ_SET_FPGA_REGS: - if (!(setup->bRequestType & USB_DIR_IN) && creg && this->fgparegs) - { - ::read(fd, buffer, setup->wLength); - if (!write_regs(regs, regindex, creg, this->fgparegs)) - return false; - return true; - } - break; - - case USB_REQ_GET_MOTOR_REGS: - if ((setup->bRequestType & USB_DIR_IN) && creg && this->motorregs) - { - if (!read_regs(regs, regindex, creg, this->motorregs)) - return false; - ::write(fd, buffer, setup->wLength); - return true; - } - break; - case USB_REQ_SET_MOTOR_REGS: - if (!(setup->bRequestType & USB_DIR_IN) && creg && this->motorregs) - { - ::read(fd, buffer, setup->wLength); - if (!write_regs(regs, regindex, creg, this->motorregs)) - return false; - return true; - } - break; - - case USB_REQ_GET_DEV_REGS: - if ((setup->bRequestType & USB_DIR_IN) && creg && this->devregs) - { - if (!read_regs(regs, regindex, creg, this->devregs)) - return false; - ::write(fd, buffer, setup->wLength); - return true; - } - break; - case USB_REQ_SET_DEV_REGS: - if (!(setup->bRequestType & USB_DIR_IN) && creg && this->devregs) - { - ::read(fd, buffer, setup->wLength); - if (!write_regs(regs, regindex, creg, this->devregs)) - return false; - return true; - } - break; - case USB_REQ_ACCES_DEV_LOG: - if (setup->wLength != 64) - return false; - - if (!(setup->bRequestType & USB_DIR_IN)) - { - ::read(fd, buffer, setup->wLength); - buffer[64 - 1] = 0; - logstring = (char *)buffer; - return true; - } - else - { - memset(buffer, 0, 64); - if (!logstring.empty()) - memcpy(buffer, logstring.data(), logstring.size()); - ::write(fd, buffer, setup->wLength); - return true; - } - break; - - case USB_REQ_GET_DEV_LOG: - if ((setup->wLength == 4) && (setup->bRequestType & USB_DIR_IN) && log_get_level(logstring, regindex, *((int *)regs))) - { - ::write(fd, buffer, setup->wLength); - return true; - } - break; - case USB_REQ_SET_DEV_LOG: - if ((setup->wLength == 4) && !(setup->bRequestType & USB_DIR_IN)) - { - ::read(fd, buffer, setup->wLength); - return log_set_level(logstring, regindex, *((int *)regs)); - } - break; - default: - break; - } - - return false; - }; - - auto connected_call = [this](bool connected) - { - printf("PNP event: %s\n", connected ? "connected" : "disconnect"); - notify()->clear(); - if (m_usbconnect) - m_usbconnect(connected); - LOG_TRACE(string_format("connect status:%s", connected ? "connected" : "disconnect")); - }; - - usb.reset(new UsbDevice(ctrl_handle, connected_call)); -} - -UsbService::~UsbService() -{ -} - -std::shared_ptr UsbService::transmiter() -{ - return transmit ? transmit : (transmit = std::shared_ptr(new UsbTransmit(usb))); -} - -std::shared_ptr UsbService::receiver() -{ - return receiv ? receiv : (receiv = std::shared_ptr(new UsbReceive(usb))); -} -void UsbService::set_scannerregs(std::shared_ptr scannerregs) -{ - scanner_ = scannerregs.get(); - this->devregs = dynamic_cast(scanner_); -} - -std::shared_ptr UsbService::notify() -{ - return noti ? noti : (noti = std::shared_ptr(new UsbNotify(usb))); -} - -void UsbService::set_onconnect_call(std::function usbhotplugcall) -{ - m_usbconnect = usbhotplugcall; -} \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/usbservice.h b/device/gxx-linux/testusb/usb-rk3399/usbservice.h deleted file mode 100644 index 2040aff..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/usbservice.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include -#include -#include -#include - -class IRegsAccess; - -class UsbDevice; -class INotify; -class ITransmit; -class IReceive; -class ScannerRegAccess; - -class UsbService -{ - ScannerRegAccess* scanner_; - -public: - UsbService(std::shared_ptr fgparegs, std::shared_ptr motorregs, std::shared_ptr scannerregs = nullptr); - virtual ~UsbService(); - - - std::shared_ptr transmiter(); - std::shared_ptr notify(); - std::shared_ptr receiver(); - void set_onconnect_call(std::function usbhotplugcall); - void set_scannerregs(std::shared_ptr scannerregs); - -private: - std::shared_ptr usb; - std::shared_ptr fgparegs; - std::shared_ptr motorregs; - IRegsAccess* devregs; - std::shared_ptr transmit; - std::shared_ptr noti; - std::shared_ptr receiv; - std::function m_usbconnect; -}; \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/usbtransmit.cpp b/device/gxx-linux/testusb/usb-rk3399/usbtransmit.cpp deleted file mode 100644 index 4456a4c..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/usbtransmit.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "usbtransmit.h" -#include "usbdevice.h" -#include -#include -#include "applog.h" -#include "memoryex.h" -#include -#include "stringex.hpp" - -static std::string loggername = "UsbTransmit"; - -UsbTransmit::UsbTransmit(std::shared_ptr usb) -{ - LOG_INIT(); - this->usb = usb; -} - -UsbTransmit::~UsbTransmit() -{ - cannel(); -} - -void UsbTransmit::write(MemoryPtr memroy) -{ - LOG_TRACE("tx start in"); - if (is_writing()) - { - LOG_TRACE("send image data error "); - printf("send image data error "); - return; - } - static int indextransfer=0; - runthread.reset(new ThreadEx([this, memroy]() { - if (usb && usb->is_connected()) - { - LOG_TRACE("tx starting"); - LOG_TRACE(string_format("tx starting transfer index =%d mmy size = %d",++indextransfer,memroy->size())); - //printf("\n tx starting transfer index =%d mmy size = %d",++indextransfer,memroy->size()); - int num= usb->write_bulk(memroy->data(), memroy->size()); - LOG_TRACE("tx end\n"); - } - })); -} - -int UsbTransmit::write_bulk(void* data,int size) -{ - int nwrite = 0; - if (usb && usb->is_connected()) - nwrite = usb->write_bulk(data, size); - return nwrite; -} - -bool UsbTransmit::is_writing() -{ - LOG_TRACE("checking UsbTransmit is_writing"); - auto ret=runthread && runthread->is_runing(); - LOG_TRACE(string_format("checking UsbTransmit done ret= %s ",ret?"true":"false")); - return ret; -} - -void UsbTransmit::cannel() -{ - if(runthread) - runthread->cannel(); -} \ No newline at end of file diff --git a/device/gxx-linux/testusb/usb-rk3399/usbtransmit.h b/device/gxx-linux/testusb/usb-rk3399/usbtransmit.h deleted file mode 100644 index bd83f5d..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/usbtransmit.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "itransmit.h" -#include -#include -#include - -class UsbDevice; - -class UsbTransmit : public ITransmit -{ -public: - UsbTransmit(std::shared_ptr usb); - virtual ~UsbTransmit() override; - virtual void write(MemoryPtr memroy) override; - virtual bool is_writing() override; - virtual void cannel() override; - virtual int write_bulk(void* data,int size) override; -private: - std::shared_ptr usb; - std::shared_ptr runthread; - -}; diff --git a/device/gxx-linux/testusb/usb-rk3399/xmake.lua b/device/gxx-linux/testusb/usb-rk3399/xmake.lua deleted file mode 100644 index 16c06a6..0000000 --- a/device/gxx-linux/testusb/usb-rk3399/xmake.lua +++ /dev/null @@ -1,11 +0,0 @@ -add_rules("mode.debug", "mode.release") - -target("gusb") - set_kind("static") - add_syslinks("pthread") - add_files("*.cpp", "src/*.cpp", "src/common/*.cpp") - add_includedirs("inc") - add_includedirs("src/common") - add_includedirs(".", { public = true}) - add_packages("common") - add_deps("regs", "gimgproc", "applog") \ No newline at end of file diff --git a/device/gxx-linux/testwakeup/main.cpp b/device/gxx-linux/testwakeup/main.cpp new file mode 100644 index 0000000..d2c2604 --- /dev/null +++ b/device/gxx-linux/testwakeup/main.cpp @@ -0,0 +1,50 @@ +#include +#include +#include "scanner.h" +#include "scannerregs.h" +#include "usbservice.h" +#include "motorboard.h" +#include "ICapturer.h" +#include "Capturer.h" +#include "MonoCapturer.h" +#include "imageusbhandler.h" +#include "uartregsaccess.h" +#include "wakeup.hpp" + +using namespace std; + +int main() +{ + remove("./out.text"); + std::shared_ptr wake; + wake.reset(new WakeUp()); + std::shared_ptr uart; + wake->power_off(); + uint reg_val = 0; + std::uint64_t index =0; + std::uint64_t error =0; + while(true) + { + index++; + std::this_thread::sleep_for(std::chrono::seconds(600)); + wake->power_on(); + std::this_thread::sleep_for(std::chrono::seconds(3)); + uart.reset(new UartRegsAccess("/dev/ttyUSB0", 921600, 0x03, 0x83)); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if(!uart->read(15,reg_val)) + { + error++; + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + uart.reset(); + std::this_thread::sleep_for(std::chrono::seconds(120)); + wake->power_off(); + std::string str = "测试次数 = "+to_string(index)+" 异常次数 = "+to_string(error); + printf("\n%s",str.c_str()); + std::ofstream o("./out.text"); + o << str; + o.close(); + + } + return 0; +} \ No newline at end of file diff --git a/device/gxx-linux/testwakeup/xmake.lua b/device/gxx-linux/testwakeup/xmake.lua new file mode 100644 index 0000000..4dc81e6 --- /dev/null +++ b/device/gxx-linux/testwakeup/xmake.lua @@ -0,0 +1,8 @@ +add_rules("mode.debug", "mode.release") + +target("testwakeup") + set_kind("binary") + add_files("*.cpp") + add_syslinks("pthread") + add_deps("gscanner","regs") + add_packages("common") \ No newline at end of file diff --git a/device/gxx-linux/tinyfsm-master/COPYING b/device/gxx-linux/tinyfsm-master/COPYING new file mode 100644 index 0000000..11104ae --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/COPYING @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2012-2018 Axel Burri + +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/device/gxx-linux/tinyfsm-master/ChangeLog b/device/gxx-linux/tinyfsm-master/ChangeLog new file mode 100644 index 0000000..1742bf2 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/ChangeLog @@ -0,0 +1,33 @@ +tinyfsm-0.3.2 + + * Add TINYFSM_NOSTDLIB compile option. + * Remove static asserts on transit functions. + * Fix elevator example. + +tinyfsm-0.3.1 + + * Bugfix (workaround) for compiler bug in gcc < 7.0: define template + specialization for FSM_INITIAL_STATE in "namespace tinyfsm" block. + +tinyfsm-0.3.0 + + * Bugfix: set initial state on all state machines before entering + states in FsmList::start(). + * Add Fsm::start() function (identical interface as FsmList). + * Add reset() functionality to Fsm and FsmList class. + * Add MooreMachine and MealyMachine class. + * Add API examples: simple_switch, resetting_switch, multiple_switch, + debugging_switch, mealy_machine, moore_machine. + * Relax access specifiers for Fsm::state() access function. + * Remove debug code. + +tinyfsm-0.2.0 + + * Use Fsm::initialize() for initialization (instead of + Fsm::initial_state). + * Change license to MIT + +tinyfsm-0.1.0 + + * Initial revision + * Note that this release was originally named "v0.10" diff --git a/device/gxx-linux/tinyfsm-master/README.md b/device/gxx-linux/tinyfsm-master/README.md new file mode 100644 index 0000000..c2aa9af --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/README.md @@ -0,0 +1,95 @@ +TinyFSM +======= + +TinyFSM is a simple finite state machine library for C++, designed for +optimal performance and low memory footprint. This makes it ideal for +real-time operating systems. The concept is very simple, allowing the +programmer to fully understand what is happening behind the scenes. It +provides a straightforward way of mapping your state machine charts +into source code. + +TinyFSM basically wraps event dispatching into function calls, making +event dispatching equally fast to calling (or even inlining) a +function. Even in the worst case, dispatching leads to nothing more +than a single vtable lookup and function call! + +Key Features: + + - Entry/exit actions + - Event actions + - Transition functions + - Transition conditions + - Event payload (classes) + - Inheritance of states and action functions + +TinyFSM benefits from the C++11 template metaprogramming features like +variadic templates, and does not depend on RTTI, exceptions or any +external library. + + +Official home page: + +Current version: `0.3.2` + + +Documentation +------------- + +You can find the main documentation in the `doc/` directory of the +TinyFSM project. The latest version is also available +[online](https://digint.ch/tinyfsm/doc/introduction.html). + + +Installation +------------ + +TinyFSM is a header-only library, no special installation steps are +needed. Just point your compiler to the "include" directory. + + +Donate +------ + +So TinyFSM has proven useful for you? + +I will definitively continue developing TinyFSM for free, but if you +want to support me you can do so: + +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QZQE9HY6QHDHS) + + +Development +----------- + +The source code for TinyFSM is managed using Git: + + git clone https://dev.tty0.ch/tinyfsm.git + +Mirror on GitHub: + + git clone https://github.com/digint/tinyfsm.git + +If you would like to contribute or have found bugs, visit the [TinyFSM +project page on GitHub] and use the [issues tracker] there. + + [TinyFSM project page on GitHub]: http://github.com/digint/tinyfsm + [issues tracker]: http://github.com/digint/tinyfsm/issues + + +Contact +------- + +For questions and suggestions regarding TinyFSM, success or failure +stories, and any other kind of feedback, please feel free to contact +the author (the email address can be found in the sources). + + +License +------- + +TinyFSM is [Open Source] software. It may be used for any purpose, +including commercial purposes, at absolutely no cost. It is +distributed under the terms of the [MIT license]. + + [Open Source]: http://www.opensource.org/docs/definition.html + [MIT license]: http://www.opensource.org/licenses/mit-license.html diff --git a/device/gxx-linux/tinyfsm-master/doc/10-Introduction.md b/device/gxx-linux/tinyfsm-master/doc/10-Introduction.md new file mode 100644 index 0000000..b9186f3 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/doc/10-Introduction.md @@ -0,0 +1,28 @@ +Introduction +============ + +TinyFSM is a simple finite state machine library for C++, designed for +optimal performance and low memory footprint. This makes it ideal for +real-time operating systems. The concept is very simple, allowing the +programmer to fully understand what is happening behind the scenes. It +provides a straightforward way of mapping your state machine charts +into source code. + +TinyFSM basically wraps event dispatching into function calls, making +event dispatching equally fast to calling (or even inlining) a +function. Even in the worst case, dispatching leads to nothing more +than a single vtable lookup and function call! + +Key Features +------------ + +- Entry/exit actions +- Event actions +- Transition functions +- Transition conditions +- Event payload (classes) +- Inheritance of states and action functions + +TinyFSM benefits from the C++11 template metaprogramming features like +variadic templates, and does not depend on RTTI, exceptions or any +external library. diff --git a/device/gxx-linux/tinyfsm-master/doc/20-Installation.md b/device/gxx-linux/tinyfsm-master/doc/20-Installation.md new file mode 100644 index 0000000..78fa3f1 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/doc/20-Installation.md @@ -0,0 +1,68 @@ +Installation +============ + +TinyFSM is an header-only library, no special installation steps are +needed. Just point your compiler to the "include" directory, and in +your source files: + + #include + + +Prerequisites +------------- + +TinyFSM requires a compiler supporting the C++11 language standard +("-std=c++11" in gcc). + +TinyFSM does not depend on RTTI, exceptions or any external library. +If you need to compile without standard libraries (e.g. in conjunction +with `-nostdlib` linker option), add `-DTINYFSM_NOSTDLIB` to the +compiler options: this removes all dependencies on the standard +library by disabling some compile-time type checks. + + +Building the Elevator Example +----------------------------- + +Change to the elevator example directory and compile the sources: + + $ cd examples/elevator + $ make + +Our elevator has call buttons on every floor, sensors reporting the +current position, and an alarm button for emergency. These actors can +be triggered via a simple command interface: + + $ ./elevator + Motor: stopped + Motor: stopped + c=Call, f=FloorSensor, a=Alarm, q=Quit ? + +Let's call the elevator to floor 2: + + c=Call, f=FloorSensor, a=Alarm, q=Quit ? c + Floor ? 2 + Motor: moving up + c=Call, f=FloorSensor, a=Alarm, q=Quit ? + +Now the elevator is moving up, and we need to trigger the floor sensor: + + c=Call, f=FloorSensor, a=Alarm, q=Quit ? f + Floor ? 1 + Reached floor 1 + c=Call, f=FloorSensor, a=Alarm, q=Quit ? f + Floor ? 2 + Reached floor 2 + Motor: stopped + c=Call, f=FloorSensor, a=Alarm, q=Quit ? + +Now we simulate a sensor defect: + + c=Call, f=FloorSensor, a=Alarm, q=Quit ? c + Floor ? 1 + Motor: moving down + c=Call, f=FloorSensor, a=Alarm, q=Quit ? f + Floor ? 2 + Floor sensor defect (expected 1, got 2) + *** calling maintenance *** + Motor: stopped diff --git a/device/gxx-linux/tinyfsm-master/doc/30-Concepts.md b/device/gxx-linux/tinyfsm-master/doc/30-Concepts.md new file mode 100644 index 0000000..b0853d6 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/doc/30-Concepts.md @@ -0,0 +1,38 @@ +Concepts +======== + +Keep it Simple +-------------- + +By design, TinyFSM implements only the very basics needed for +designing state machines. For many people, it is important to know +what a library is doing when making a decision for a specific library. + + +State Definition +---------------- + +States are derived classes from a base FSM state, providing react() +functions for every event, as well as entry() and exit() functions. + + +Event Dispatching +----------------- + +TinyFSM does not hold state/event function tables like most other +state machine processors do. Instead, it keeps a pointer to the +current state (having the type of the state machine base +class). Dispatching an event simply calls the react() function of the +current state, with the event class as argument. This results in a +single vtable lookup and a function call, which is very efficient! + +Event dispatching on an FsmList<> are simply dispatch() calls to all +state machines in the list. + + +Header-Only Library +------------------- + +The TinyFSM library consist entirely of header files containing +templates, and requires no separately-compiled library binaries or +special treatment when linking. diff --git a/device/gxx-linux/tinyfsm-master/doc/40-Usage.md b/device/gxx-linux/tinyfsm-master/doc/40-Usage.md new file mode 100644 index 0000000..5ad931b --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/doc/40-Usage.md @@ -0,0 +1,238 @@ +Usage +===== + +Refer to the [API examples](/examples/api/) provided with the TinyFSM +package for a quick overview. Recommended starting points: + + - [Simple Switch](/examples/api/simple_switch.cpp) + - [Moore Machine](/examples/api/moore_machine.cpp) + - [Elevator Project](/examples/elevator/) + +For an example in an RTOS environment, see the [stm32f103stk-demo] of +the [OpenMPTL] project. Starting points: + + - [screen.hpp](https://github.com/digint/openmptl/tree/master/projects/stm32f103stk-demo/src/screen.hpp) + : TinyFSM declarations. + - [kernel.cpp](https://github.com/digint/openmptl/tree/master/projects/stm32f103stk-demo/src/kernel.cpp) + : Poll input and trigger events. + + [OpenMPTL]: https://digint.ch/openmptl/ + [stm32f103stk-demo]: https://github.com/digint/openmptl/tree/master/projects/stm32f103stk-demo + + +The examples in the documentation below are mainly based on the +"Elevator Project" example. + + +### 1. Declare Events + +Declare events that your state machine will listen to. Events are +classes derived from the tinyfsm::Event class. + +Example: + + struct FloorEvent : tinyfsm::Event + { + int floor; + }; + + struct Call : FloorEvent { }; + struct FloorSensor : FloorEvent { }; + struct Alarm : tinyfsm::Event { }; + +In the example above, we declare three events. Note that events are +regular classes, which are passed as arguments to the react() members +of a state class. In this example, we use a member variable "floor", +which is used to specify the floor number on "Call" and "FloorSensors" +events. + + +### 2. Declare the State Machine Class + +Declare your state machine class. State machines are classes derived +from the tinyfsm::Fsm template class, where T is the type name of the +state machine itself. + +You need to declare the following public members: + + - react() function for each event + - entry() and exit() functions + +Example: + + class Elevator + : public tinyfsm::Fsm + { + public: + /* default reaction for unhandled events */ + void react(tinyfsm::Event const &) { }; + + virtual void react(Call const &); + virtual void react(FloorSensor const &); + void react(Alarm const &); + + virtual void entry(void) { }; /* entry actions in some states */ + void exit(void) { }; /* no exit actions */ + }; + + +Note that you are free to declare the functions non-virtual if you +like. This has implications on the execution speed: In the example +above, the react(Alarm) function is declared non-virtual, as all states +share the same reaction for this event. This makes code execution +faster when dispatching the "Alarm" event, since no vtable lookup is +needed. + + +### 3. Declare the States + +Declare the states of your state machine. States are classes derived +from the state machine class. + +Note that state classes are *implicitly instantiated*. If you want to +reuse states in multiple state machines, you need to declare them as +templates (see `/examples/api/multiple_switch.cpp`). + +Example: + + class Panic + : public Elevator + { + void entry() override; + }; + + class Moving + : public Elevator + { + void react(FloorSensor const &) override; + }; + + class Idle + : public Elevator + { + void entry() override; + void react(Call const & e) override; + }; + + +In this example, we declare three states. Note that the "elevator" +example source code does not declare the states separately, but rather +defines the code directly in the declaration. + + +### 4. Implement Actions and Event Reactions + +In most cases, event reactions consist of one or more of the following +steps: + + - Change some local data + - Send events to other state machines + - Transit to different state + +**Important**: +Make sure that the `transit<>()` function call is the last command +executed within a reaction function! + +**Important**: +Don't use `transit<>()` in entry/exit actions! + +Example: + + void Idle::entry() { + send_event(MotorStop()); + } + + void Idle::react(Call const & e) { + dest_floor = e.floor; + + if(dest_floor == current_floor) + return; + + /* lambda function used for transition action */ + auto action = [] { + if(dest_floor > current_floor) + send_event(MotorUp()); + else if(dest_floor < current_floor) + send_event(MotorDown()); + }; + + transit(action); + }; + + +In this example, we use a lambda function as transition action. The +`transit<>()` function does the following: + + 1. Call the exit() function of the current state + 2. Call the the transition action if provided + 3. Change the current state to the new state + 4. Call the entry() function of the new state + +Note that you can also pass condition functions to the `transit<>()` +function. + + +### 5. Define the Initial State + +Use the macro `FSM_INITIAL_STATE(fsm, state)` for defining the initial +state (or "start state") of your state machine: + +Example: + + FSM_INITIAL_STATE(Elevator, Idle) + +This sets the current state of the "Elevator" state machine to "Idle". +More specifially, it defines a template specialization for +`Fsm::set_initial_state()`, setting the current state to +Idle. + + +### 6. Define Custom Initialization + +If you need to perform custom initialization, you can override the +reset() member function in your state machine class. If you are using +state variables, you can re-instantiate your states by calling +`tinyfsm::StateList::reset()`. + +Example: + + class Switch : public tinyfsm::Fsm + { + public: static void reset(void) { + tinyfsm::StateList::reset(); // reset all states + myvar = 0; + ... + } + ... + } + +Make sure to always set the current state, or you'll end up with a +null pointer dereference. + + +### 7. Use FsmList for Event Dispatching + +You might have noticed some calls to a send_event() function in the +example above. This is NOT a function provided with TinyFSM. Since +event dispatching can be implemented in several ways, TinyFSM leaves +this open to you. The "elevator" example implements the send_event() +function as *direct event dispatching*, without using event +queues. This has the advantage that execution is much faster, since no +RTTI is needed and the decision which function to call for an event +class is made at compile-time. On the other hand, special care has to +be taken when designing the state machines, in order to avoid loops. + +Code from "fsmlist.hpp": + + typedef tinyfsm::FsmList fsm_list; + + template + void send_event(E const & event) + { + fsm_list::template dispatch(event); + } + +Here, send_event() dispatches events to all state machines in the +list. It is important to understand that this approach comes with no +performance penalties at all, as long as the default reaction is +defined empty within the state machine declaration. diff --git a/device/gxx-linux/tinyfsm-master/doc/50-API.md b/device/gxx-linux/tinyfsm-master/doc/50-API.md new file mode 100644 index 0000000..44fcf17 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/doc/50-API.md @@ -0,0 +1,206 @@ +API Reference +============= + +`#include ` + + +Class Diagram +------------- + ....... + +--------------------------------------: T : + | tinyfsm::FsmList :.....: + +-----------------------------------------| + | [+] set_initial_state() <> | + | [+] reset() <> | + | [+] enter() <> | + | [+] start() <> | + | [+] dispatch(Event) <> | + +-----------------------------------------+ + + + ....... + +--------------------------------------: T : + | tinyfsm::Fsm :.....: + +-----------------------------------------| + | [+] state() <> | + | [+] set_initial_state() <> | + | [+] reset() <> | + | [+] enter() <> | + | [+] start() <> | + | [+] dispatch(Event) <> | + | [#] transit() | + | [#] transit(Action) | + | [#] transit(Action, Condition) | + +-----------------------------------------+ + # + | + | + +---------------------+ + | MyFSM | + +---------------------+ + | [+] entry() | + | [+] exit() | + | [+] react(EventX) | + | [+] react(EventY) | + | ... | + +---------------------+ + # + | + +-------------+-------------+ + | | | + +---------+ +---------+ +---------+ + | State_A | | State_B | | ... | + +---------+ +---------+ +---------+ + + + [#] protected + [+] public + [-] private + + +template< typename F > class Fsm +-------------------------------- + +### State Machine Functions + + * `template< typename S > static constexpr S & state(void)` + + Returns a reference to a (implicitly instantiated) state S. Allows + low-level access to all states; + + + * `static void set_initial_state(void)` + + Function prototype, must be defined (explicit template + specialization) for every state machine class (e.g. by using the + `FSM_INITIAL_STATE(fsm, state`) macro). Sets current state to + initial (start) state. + + + * `static void reset(void)` + + Empty function, can be overridden by state machine class in order to + perform custom initialization (e.g. set static state machine + variables, or reset states using `StateList::reset()`) + or directly via the `state()` instance). + + Note that this function is NOT called on start(). + + See example: `/examples/api/resetting_switch.cpp` + + * `static void enter(void)` + + Helper function, usually not needed to be used directly: + calls entry() function of current state. + + + * `static void start()` + + Sets the initial (start) state and calls its entry() function. + + + * `template< typename E > static void dispatch(E const &)` + + Dispatch an event to the current state of this state machine. + + +### State Transition Functions + + * `template< typename S > void transit(void)` + + Transit to a new state: + + 1. Call exit() function on current state + 2. Set new current state to S + 3. Call entry() function on new state + + + * `template< typename S, typename ActionFunction > void transit(ActionFunction)` + + Transit to a new state, with action function: + + 1. Call exit() function on current state + 2. Call ActionFunction + 3. Set new current state to S + 4. Call entry() function on new state + + + * `template< typename S, typename ActionFunction, typename ConditionFunction > void transit(ActionFunction, ConditionFunction)` + + Transit to a new state only if ConditionFunction returns true. + Shortcut for: `if(ConditionFunction()) transit(ActionFunction);`. + + +### Derived Classes + +#### template< typename F > class MooreMachine + +Moore state machines have entry actions, but no exit actions: + + * `virtual void entry(void) { }` + + Entry action, not enforcing. Can be enforced by declaring pure + virtual: `virtual void entry(void) = 0` + + * `void exit(void) { }` + + No exit actions. + +See example: `/examples/api/more_machine.cpp` + +#### template< typename F > class MealyMachine + +Mealy state machines do not have entry/exit actions: + + * `void entry(void) { }` + + No entry actions. + + * `void exit(void) { }` + + No exit actions. + +*Input actions* are modeled in react(), conditional dependent of event +type or payload and using `transit<>(ActionFunction)`. + +See example: `/examples/api/mealy_machine.cpp` + + +template< typename... FF > struct FsmList +----------------------------------------- + + * `static void set_initial_state(void)` + + Calls set_initial_state() on all state machines in the list. + + + * `static void reset()` + + Calls reset() on all state machines in the list. + + + * `static void enter()` + + Calls enter() on all state machines in the list. + + + * `static void start()` + + Sets the initial (start) state for all state machines in list, then + call all entry() functions. + + + * `template< typename E > static void dispatch(E const &)` + + Dispatch an event to the current state of all the state machines in + the list. + + +template< typename... SS > struct StateList +------------------------------------------- + + * `static void reset(void)` + + Re-instantiate all states in the list, using copy-constructor. + + See example: `/examples/api/resetting_switch.cpp` diff --git a/device/gxx-linux/tinyfsm-master/doc/60-Development.md b/device/gxx-linux/tinyfsm-master/doc/60-Development.md new file mode 100644 index 0000000..24ad0e1 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/doc/60-Development.md @@ -0,0 +1,26 @@ +Development +=========== + +Source Code Repository +---------------------- + +The source code for TinyFSM is managed using Git: + + git clone https://dev.tty0.ch/tinyfsm.git + +Mirror on GitHub: + + git clone https://github.com/digint/tinyfsm.git + + +How to Contribute +----------------- + +Your contributions are welcome! + +If you would like to contribute or have found bugs, visit the [TinyFSM +project page on GitHub] and use the [issues tracker] there, or contact +the author via email. + + [TinyFSM project page on GitHub]: http://github.com/digint/tinyfsm + [issues tracker]: http://github.com/digint/tinyfsm/issues diff --git a/device/gxx-linux/tinyfsm-master/doc/70-License.md b/device/gxx-linux/tinyfsm-master/doc/70-License.md new file mode 100644 index 0000000..6a4da72 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/doc/70-License.md @@ -0,0 +1,9 @@ +License +======= + +TinyFSM is [Open Source] software. It may be used for any purpose, +including commercial purposes, at absolutely no cost. It is +distributed under the terms of the [MIT license]. + + [Open Source]: http://www.opensource.org/docs/definition.html + [MIT license]: http://www.opensource.org/licenses/mit-license.html diff --git a/device/gxx-linux/tinyfsm-master/examples/api/Makefile b/device/gxx-linux/tinyfsm-master/examples/api/Makefile new file mode 100644 index 0000000..63b110e --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/Makefile @@ -0,0 +1,63 @@ +# Compiler prefix, in case your default compiler does not implement all C++11 features: +#CROSS = /opt/toolchain/x86_64-pc-linux-gnu-gcc-4.7.0/bin/x86_64-pc-linux-gnu- + +# HINT: g++ -Q -O2 --help=optimizers +OPTIMIZER = -Os + +CC = $(CROSS)gcc +CXX = $(CROSS)g++ +SIZE = size -d +RM = rm -f + +SRC_DIRS = . +INCLUDE = -I ../../include + +SRCS = $(wildcard $(addsuffix /*.cpp, $(SRC_DIRS))) +OBJS = $(SRCS:.cpp=.o) +DEPENDS = $(OBJS:.o=.d) + +EXE = $(SRCS:.cpp=) + + +#------------------------------------------------------------------------------ +# flags +# + +FLAGS += $(INCLUDE) +FLAGS += -MMD + +CXXFLAGS = $(FLAGS) +CXXFLAGS += $(OPTIMIZER) +CXXFLAGS += -std=c++11 +CXXFLAGS += -fno-exceptions +CXXFLAGS += -fno-rtti + +CXXFLAGS += -Wall -Wextra +CXXFLAGS += -Wctor-dtor-privacy +CXXFLAGS += -Wcast-align -Wpointer-arith -Wredundant-decls +CXXFLAGS += -Wshadow -Wcast-qual -Wcast-align -pedantic + +# Produce debugging information (for use with gdb) +#OPTIMIZER = -Og +#FLAGS += -g + +# Use LLVM +#CXX = $(CROSS)clang++ +#CXXFLAGS += -stdlib=libc++ +#LDFLAGS += -lc++ + + +.PHONY: all clean + +all: $(EXE) + +%: %.cpp + $(CXX) $(CXXFLAGS) -o $@ $< + $(SIZE) $@ + +clean: + $(RM) *.d + $(RM) $(EXE) + + +-include $(DEPENDS) diff --git a/device/gxx-linux/tinyfsm-master/examples/api/debugging_switch b/device/gxx-linux/tinyfsm-master/examples/api/debugging_switch new file mode 100644 index 0000000000000000000000000000000000000000..85734374993708ebc6331afb1dd3f2c632fd0c38 GIT binary patch literal 16144 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 +#include +#include + +struct Off; // forward declaration + + +// ---------------------------------------------------------------------------- +// Event Declarations +// +struct Toggle : tinyfsm::Event { }; // Event Declarations + + +// ---------------------------------------------------------------------------- +// State Machine Declaration +// +struct Switch +: tinyfsm::Fsm +{ + static void reset(void); + + // NOTE: on reset: "tinyfsm::StateList::reset()", copy + // constructor is used by default, so "this" points to neither + // "Off" nor "On" (see operator=() below). + Switch() : counter(0) { + std::cout << "* Switch()" << std::endl + << " this = " << this << std::endl; + } + + ~Switch() { + std::cout << "* ~Switch()" << std::endl + << " this = " << this << std::endl; + } + + Switch & operator=(const Switch & other) { + std::cout << "* operator=()" << std::endl + << " this = " << this << std::endl + << " other = " << &other << std::endl; + counter = other.counter; + return *this; + } + + virtual void react(Toggle const &) { }; + void entry(void); + void exit(void); + + int counter; +}; + +struct On : Switch { + void react(Toggle const &) override { transit(); }; +}; + +struct Off : Switch { + void react(Toggle const &) override { transit(); }; +}; + +FSM_INITIAL_STATE(Switch, Off) + + +// ---------------------------------------------------------------------------- +// State Machine Definitions +// +void Switch::reset() { + tinyfsm::StateList::reset(); +} + +void Switch::entry() { + counter++; + + // debugging only. properly designed state machines don't need this: + if(is_in_state()) { std::cout << "* On::entry()" << std::endl; } + else if(is_in_state()) { std::cout << "* Off::entry()" << std::endl; } + else assert(true); + + assert(current_state_ptr == this); + std::cout << " this (cur) = " << this << std::endl + << " state = " << &state() << std::endl + << " state = " << &state() << std::endl; +} + +void Switch::exit() { + assert(current_state_ptr == this); + std::cout << "* exit()" << std::endl + << " this (cur) = " << this << std::endl + << " state = " << &state() << std::endl + << " state = " << &state() << std::endl; +} + + +// ---------------------------------------------------------------------------- +// Main +// +int main() +{ + Switch::start(); + + while(1) + { + char c; + std::cout << "* main()" << std::endl + << " cur_counter = " << Switch::current_state_ptr->counter << std::endl + << " on_counter = " << Switch::state().counter << std::endl + << " off_counter = " << Switch::state().counter << std::endl; + + std::cout << std::endl << "t=Toggle, r=Restart, q=Quit ? "; + std::cin >> c; + switch(c) { + case 't': + Switch::dispatch(Toggle()); + break; + case 'r': + Switch::reset(); + Switch::start(); + break; + case 'q': + return 0; + default: + std::cout << "> Invalid input" << std::endl; + }; + } +} diff --git a/device/gxx-linux/tinyfsm-master/examples/api/debugging_switch.d b/device/gxx-linux/tinyfsm-master/examples/api/debugging_switch.d new file mode 100644 index 0000000..8c573ee --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/debugging_switch.d @@ -0,0 +1 @@ +debugging_switch: debugging_switch.cpp ../../include/tinyfsm.hpp diff --git a/device/gxx-linux/tinyfsm-master/examples/api/mealy_machine b/device/gxx-linux/tinyfsm-master/examples/api/mealy_machine new file mode 100644 index 0000000000000000000000000000000000000000..94c58a651563bbe574323a98534033291972379e GIT binary patch literal 14840 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 literal 0 HcmV?d00001 diff --git a/device/gxx-linux/tinyfsm-master/examples/api/mealy_machine.cpp b/device/gxx-linux/tinyfsm-master/examples/api/mealy_machine.cpp new file mode 100644 index 0000000..a4fadff --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/mealy_machine.cpp @@ -0,0 +1,70 @@ +#include +#include + +// ---------------------------------------------------------------------------- +// 1. Event Declarations +// +struct Toggle : tinyfsm::Event { }; + + +// ---------------------------------------------------------------------------- +// 2. State Machine Base Class Declaration +// +struct Switch : tinyfsm::MealyMachine +{ + /* pure virtual reaction (override required in all states) */ + virtual void react(Toggle const &) = 0; + + /* transition actions */ + static void OpenCircuit() { + std::cout << "* Opening ciruit (light goes OFF)" << std::endl; + } + static void CloseCircuit() { + std::cout << "* Closing ciruit (light goes ON)" << std::endl; + } +}; + + +// ---------------------------------------------------------------------------- +// 3. State Declarations +// +struct Off; // forward declaration + +struct On : Switch +{ + void react(Toggle const &) override { transit(OpenCircuit); }; +}; + +struct Off : Switch +{ + void react(Toggle const &) override { transit(CloseCircuit); }; +}; + +FSM_INITIAL_STATE(Switch, Off) + + +// ---------------------------------------------------------------------------- +// Main +// +int main() +{ + Switch::start(); + + std::cout << "> You are facing a light switch..." << std::endl; + while(1) + { + char c; + std::cout << std::endl << "t=Toggle, q=Quit ? "; + std::cin >> c; + switch(c) { + case 't': + std::cout << "> Toggling switch..." << std::endl; + Switch::dispatch(Toggle()); + break; + case 'q': + return 0; + default: + std::cout << "> Invalid input" << std::endl; + }; + } +} diff --git a/device/gxx-linux/tinyfsm-master/examples/api/mealy_machine.d b/device/gxx-linux/tinyfsm-master/examples/api/mealy_machine.d new file mode 100644 index 0000000..c533fc6 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/mealy_machine.d @@ -0,0 +1 @@ +mealy_machine: mealy_machine.cpp ../../include/tinyfsm.hpp diff --git a/device/gxx-linux/tinyfsm-master/examples/api/moore_machine b/device/gxx-linux/tinyfsm-master/examples/api/moore_machine new file mode 100644 index 0000000000000000000000000000000000000000..952131338507ee0132fe0be316df88fea8e241d4 GIT binary patch literal 14968 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 literal 0 HcmV?d00001 diff --git a/device/gxx-linux/tinyfsm-master/examples/api/moore_machine.cpp b/device/gxx-linux/tinyfsm-master/examples/api/moore_machine.cpp new file mode 100644 index 0000000..02a77da --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/moore_machine.cpp @@ -0,0 +1,64 @@ +#include +#include + +// ---------------------------------------------------------------------------- +// 1. Event Declarations +// +struct Toggle : tinyfsm::Event { }; + + +// ---------------------------------------------------------------------------- +// 2. State Machine Base Class Declaration +// +struct Switch : tinyfsm::MooreMachine +{ + /* pure virtual reaction (override required in all states) */ + virtual void react(Toggle const &) = 0; +}; + + +// ---------------------------------------------------------------------------- +// 3. State Declarations +// +struct Off; // forward declaration + +struct On : Switch +{ + void entry() override { std::cout << "* Closing ciruit (light goes ON)" << std::endl; }; + void react(Toggle const &) override { transit(); }; +}; + +struct Off : Switch +{ + void entry() override { std::cout << "* Opening ciruit (light goes OFF)" << std::endl; }; + void react(Toggle const &) override { transit(); }; +}; + +FSM_INITIAL_STATE(Switch, Off) + + +// ---------------------------------------------------------------------------- +// Main +// +int main() +{ + Switch::start(); + + std::cout << "> You are facing a light switch..." << std::endl; + while(1) + { + char c; + std::cout << std::endl << "t=Toggle, q=Quit ? "; + std::cin >> c; + switch(c) { + case 't': + std::cout << "> Toggling switch..." << std::endl; + Switch::dispatch(Toggle()); + break; + case 'q': + return 0; + default: + std::cout << "> Invalid input" << std::endl; + }; + } +} diff --git a/device/gxx-linux/tinyfsm-master/examples/api/moore_machine.d b/device/gxx-linux/tinyfsm-master/examples/api/moore_machine.d new file mode 100644 index 0000000..8c83e9b --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/moore_machine.d @@ -0,0 +1 @@ +moore_machine: moore_machine.cpp ../../include/tinyfsm.hpp diff --git a/device/gxx-linux/tinyfsm-master/examples/api/multiple_switch b/device/gxx-linux/tinyfsm-master/examples/api/multiple_switch new file mode 100644 index 0000000000000000000000000000000000000000..de41083a43248f4615dbded1f84c2776ea37d597 GIT binary patch literal 17568 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 f#DXh<{VV6i^)p6$WZZVfh?cFebLE +#include +#include /* rand */ + +template +class Off; // forward declaration + +static void DumpState(int inum, const char * state, int on_counter, int defect_level) { + std::cout << "* Switch[" << inum << "] is " << state << " (on_counter=" << on_counter << ", defect_level=" << defect_level << ")" << std::endl; +} + +// ---------------------------------------------------------------------------- +// 1. Event Declarations +// +struct Toggle : tinyfsm::Event { }; + + +// ---------------------------------------------------------------------------- +// 2. State Machine Base Class Declaration +// +template +class DefectiveSwitch +: public tinyfsm::Fsm< DefectiveSwitch > +{ +public: + static constexpr unsigned int defect_level = (inum * 2); + + static void reset(void) { + on_counter = 0; + } + + /* default reaction for unhandled events */ + void react(tinyfsm::Event const &) { }; + + virtual void react(Toggle const &) { }; + virtual void entry(void) { }; /* entry actions in some states */ + void exit(void) { }; /* no exit actions */ + +protected: + static unsigned int on_counter; +}; + +// state variable definitions +template +unsigned int DefectiveSwitch::on_counter{0}; + + +// ---------------------------------------------------------------------------- +// 3. State Declarations +// +template +class On +: public DefectiveSwitch +{ + // note: base class is not known in dependend template + using base = DefectiveSwitch; + void entry() override { + base::on_counter++; + DumpState(inum, "ON ", base::on_counter, base::defect_level); + }; + void react(Toggle const &) override { + base::template transit< Off >(); + }; +}; + + +template +class Off +: public DefectiveSwitch +{ + using base = DefectiveSwitch; + void entry() override { + DumpState(inum, "OFF", base::on_counter, base::defect_level); + }; + void react(Toggle const &) override { + if((rand() % (base::defect_level + 1)) == 0) + base::template transit< On >(); + else { + std::cout << "* Kzzz kzzzzzz" << std::endl; + base::template transit< Off >(); + } + }; +}; + +FSM_INITIAL_STATE(DefectiveSwitch<0>, Off<0> ) +FSM_INITIAL_STATE(DefectiveSwitch<1>, Off<1> ) +FSM_INITIAL_STATE(DefectiveSwitch<2>, Off<2> ) + + +// ---------------------------------------------------------------------------- +// 4. State Machine List Declaration +// + +using fsm_handle = tinyfsm::FsmList< + DefectiveSwitch<0>, + DefectiveSwitch<1>, + DefectiveSwitch<2> + >; + +template +void ToggleSingle() { + std::cout << "> Toggling switch " << inum << "..." << std::endl; + DefectiveSwitch::dispatch(Toggle()); +} + + +// ---------------------------------------------------------------------------- +// Main +// +int main() +{ + fsm_handle::start(); + + while(1) + { + char c; + std::cout << std::endl << "0,1,2=Toggle single, a=Toggle all, r=Restart, q=Quit ? "; + std::cin >> c; + switch(c) { + case '0': ToggleSingle<0>(); break; + case '1': ToggleSingle<1>(); break; + case '2': ToggleSingle<2>(); break; + case 'a': + std::cout << "> Toggling all switches..." << std::endl; + fsm_handle::dispatch(Toggle()); + break; + case 'r': + fsm_handle::reset(); + fsm_handle::start(); + break; + case 'q': + return 0; + default: + std::cout << "> Invalid input" << std::endl; + }; + } +} diff --git a/device/gxx-linux/tinyfsm-master/examples/api/multiple_switch.d b/device/gxx-linux/tinyfsm-master/examples/api/multiple_switch.d new file mode 100644 index 0000000..50c1541 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/multiple_switch.d @@ -0,0 +1 @@ +multiple_switch: multiple_switch.cpp ../../include/tinyfsm.hpp diff --git a/device/gxx-linux/tinyfsm-master/examples/api/resetting_switch b/device/gxx-linux/tinyfsm-master/examples/api/resetting_switch new file mode 100644 index 0000000000000000000000000000000000000000..fcef791d817c4f3c90b25e72f3946762b7a2aa5d GIT binary patch literal 15512 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 +#include + +class Off; // forward declaration + + +// ---------------------------------------------------------------------------- +// 1. Event Declarations +// +struct Toggle : tinyfsm::Event { }; + + +// ---------------------------------------------------------------------------- +// 2. State Machine Base Class Declaration +// +class Switch +: public tinyfsm::Fsm +{ + // entry(), exit() and react() are called from Fsm::transit() + // in derived states, make friends: + friend class tinyfsm::Fsm; + + /* default reaction for unhandled events */ + void react(tinyfsm::Event const &) { }; + + virtual void react(Toggle const &) { }; + virtual void entry(void) { }; /* entry actions in some states */ + void exit(void) { }; /* no exit actions */ + +public: + static void reset(void); /* implemented below */ +}; + + +// ---------------------------------------------------------------------------- +// 3. State Declarations +// +class On +: public Switch +{ + void entry() override { counter++; std::cout << "* Switch is ON, counter=" << counter << std::endl; }; + void react(Toggle const &) override { transit(); }; + int counter; + +public: + On() : counter(0) { std::cout << "** RESET State=On" << std::endl; } +}; + +class Off +: public Switch +{ + void entry() override { counter++; std::cout << "* Switch is OFF, counter=" << counter << std::endl; }; + void react(Toggle const &) override { transit(); }; + int counter; + +public: + Off() : counter(0) { std::cout << "** RESET State=Off" << std::endl; } +}; + + +void Switch::reset() { + std::cout << "** RESET Switch" << std::endl; + // Reset all states (calls constructor on all states in list) + tinyfsm::StateList::reset(); + + // Alternatively, make counter public above and reset the values + // here instead of using a copy-constructor with StateList<>: + //state().counter = 0; + //state().counter = 0; +} + +FSM_INITIAL_STATE(Switch, Off) + + +// ---------------------------------------------------------------------------- +// 4. State Machine List Declaration (dispatches events to multiple FSM's) +// +// In this example, we only have a single state machine, no need to use FsmList<>: +//using fsm_handle = tinyfsm::FsmList< Switch >; +using fsm_handle = Switch; + + +// ---------------------------------------------------------------------------- +// Main +// +int main() +{ + fsm_handle::start(); + + while(1) + { + char c; + std::cout << std::endl << "t=Toggle, r=Restart, q=Quit ? "; + std::cin >> c; + switch(c) { + case 't': + std::cout << "> Toggling switch..." << std::endl; + fsm_handle::dispatch(Toggle()); + break; + case 'r': + fsm_handle::reset(); + fsm_handle::start(); + break; + case 'q': + return 0; + default: + std::cout << "> Invalid input" << std::endl; + }; + } +} diff --git a/device/gxx-linux/tinyfsm-master/examples/api/resetting_switch.d b/device/gxx-linux/tinyfsm-master/examples/api/resetting_switch.d new file mode 100644 index 0000000..5d9991f --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/resetting_switch.d @@ -0,0 +1 @@ +resetting_switch: resetting_switch.cpp ../../include/tinyfsm.hpp diff --git a/device/gxx-linux/tinyfsm-master/examples/api/simple_switch b/device/gxx-linux/tinyfsm-master/examples/api/simple_switch new file mode 100644 index 0000000000000000000000000000000000000000..ad497be8a0760d435a202aa825f5b4d2a02f94de GIT binary patch literal 14968 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 literal 0 HcmV?d00001 diff --git a/device/gxx-linux/tinyfsm-master/examples/api/simple_switch.cpp b/device/gxx-linux/tinyfsm-master/examples/api/simple_switch.cpp new file mode 100644 index 0000000..b20b2ab --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/simple_switch.cpp @@ -0,0 +1,85 @@ +#include +#include + +struct Off; // forward declaration + + +// ---------------------------------------------------------------------------- +// 1. Event Declarations +// +struct Toggle : tinyfsm::Event { }; + + +// ---------------------------------------------------------------------------- +// 2. State Machine Base Class Declaration +// +struct Switch : tinyfsm::Fsm +{ + virtual void react(Toggle const &) { }; + + // alternative: enforce handling of Toggle in all states (pure virtual) + //virtual void react(Toggle const &) = 0; + + virtual void entry(void) { }; /* entry actions in some states */ + void exit(void) { }; /* no exit actions */ + + // alternative: enforce entry actions in all states (pure virtual) + //virtual void entry(void) = 0; +}; + + +// ---------------------------------------------------------------------------- +// 3. State Declarations +// +struct On : Switch +{ + void entry() override { std::cout << "* Switch is ON" << std::endl; }; + void react(Toggle const &) override { transit(); }; +}; + +struct Off : Switch +{ + void entry() override { std::cout << "* Switch is OFF" << std::endl; }; + void react(Toggle const &) override { transit(); }; +}; + +FSM_INITIAL_STATE(Switch, Off) + + +// ---------------------------------------------------------------------------- +// 4. State Machine List Declaration (dispatches events to multiple FSM's) +// +// In this example, we only have a single state machine, no need to use FsmList<>: +//using fsm_handle = tinyfsm::FsmList< Switch >; +using fsm_handle = Switch; + + +// ---------------------------------------------------------------------------- +// Main +// +int main() +{ + // instantiate events + Toggle toggle; + + fsm_handle::start(); + + while(1) + { + char c; + std::cout << std::endl << "t=Toggle, q=Quit ? "; + std::cin >> c; + switch(c) { + case 't': + std::cout << "> Toggling switch..." << std::endl; + fsm_handle::dispatch(toggle); + // alternative: instantiating causes no overhead (empty declaration) + //fsm_handle::dispatch(Toggle()); + break; + case 'q': + return 0; + default: + std::cout << "> Invalid input" << std::endl; + }; + } +} diff --git a/device/gxx-linux/tinyfsm-master/examples/api/simple_switch.d b/device/gxx-linux/tinyfsm-master/examples/api/simple_switch.d new file mode 100644 index 0000000..5d32110 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/api/simple_switch.d @@ -0,0 +1 @@ +simple_switch: simple_switch.cpp ../../include/tinyfsm.hpp diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/Makefile b/device/gxx-linux/tinyfsm-master/examples/elevator/Makefile new file mode 100644 index 0000000..4c97905 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/elevator/Makefile @@ -0,0 +1,98 @@ +# Compiler prefix, in case your default compiler does not implement all C++11 features: +#CROSS = /opt/toolchain/x86_64-pc-linux-gnu-gcc-4.7.0/bin/x86_64-pc-linux-gnu- + +PROJECT = elevator + +# HINT: g++ -Q -O2 --help=optimizers +OPTIMIZER = -Os + +CC = $(CROSS)gcc +CXX = $(CROSS)g++ +AS = $(CROSS)gcc -x assembler-with-cpp +LD = $(CROSS)g++ +OBJCOPY = $(CROSS)objcopy +OBJDUMP = $(CROSS)objdump +SIZE = size -d +RM = rm -f +RM_R = rm -rf +CP = cp +MKDIR_P = mkdir -p +DOXYGEN = doxygen + + +SRC_DIRS = . +INCLUDE = -I ../../include + +SRCS = $(wildcard $(addsuffix /*.cpp, $(SRC_DIRS))) +OBJS = $(SRCS:.cpp=.o) +DEPENDS = $(OBJS:.o=.d) + +EXE = $(PROJECT) +MAP = $(PROJECT).map + + +#------------------------------------------------------------------------------ +# flags +# + +# commmon flags propagated to CFLAGS, CXXFLAGS, ASFLAGS (not LDFLAGS) +FLAGS += $(INCLUDE) +FLAGS += -MMD + +CXXFLAGS = $(FLAGS) +CXXFLAGS += $(OPTIMIZER) +CXXFLAGS += -std=c++11 +CXXFLAGS += -fno-exceptions +CXXFLAGS += -fno-rtti + +CXXFLAGS += -Wall -Wextra +CXXFLAGS += -Wctor-dtor-privacy +CXXFLAGS += -Wcast-align -Wpointer-arith -Wredundant-decls +CXXFLAGS += -Wshadow -Wcast-qual -Wcast-align -pedantic + +LDFLAGS += -fno-exceptions +LDFLAGS += -fno-rtti + +# Produce debugging information (for use with gdb) +#OPTIMIZER = -Og +#FLAGS += -g + +# Use LLVM +#CXX = $(CROSS)clang++ +#CXXFLAGS += -stdlib=libc++ +#LDFLAGS += -lc++ + +# Enable link-time optimizer +#CXXFLAGS += -flto +#LDFLAGS += -flto + +# Strip dead code (enable garbage collection) +#OPTIMIZER += -ffunction-sections -fdata-sections +#LDFLAGS += -Wl,$(if $(shell ld -v | grep GNU),--gc-sections,-dead_strip) + +# Enable automatic template instantiation at link time +#CXXFLAGS += -frepo +#LDFLAGS += -frepo + +# Create link map file +#LDFLAGS += -Wl,-Map="$(MAP)",--cref + + +.PHONY: all clean + +all: $(EXE) + +$(EXE): $(OBJS) + $(LD) $(OBJS) $(LDFLAGS) -o $(EXE) + $(SIZE) $@ + +%.o: %.cpp + $(CXX) -c $(CXXFLAGS) -o $@ $< + +clean: + $(RM) *.o + $(RM) *.d + $(RM) $(EXE) + + +-include $(DEPENDS) diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/README.md b/device/gxx-linux/tinyfsm-master/examples/elevator/README.md new file mode 100644 index 0000000..71d5c93 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/elevator/README.md @@ -0,0 +1,88 @@ +Elevator Project +================ + +Example implementation of a simplified elevator logic, using [TinyFSM]. + + [TinyFSM]: https://digint.ch/tinyfsm/ + + +Overview +-------- + +Imagine a elevator having: + + - "Call" button on each floor, + - "Floor Sensor" on each floor, triggering an event as soon as the + elevator arrives there, + - "Alarm" button. + + +Implementation +-------------- + +The elevator example implements two state machines interacting with +each other: + + 1. Elevator + - State: Idle + - State: Moving + - State: Panic + + 2. Motor + - State: Stopped + - State: Up + - State: Down + + +[insert ascii-art here] + +A good state machine design avoids circular dependencies at all +cost: While the elevator sends events to the motor, the motor NEVER +sends events to the elevator (top-down only). + + +FAQ +--- + +Did you notice the motor starting twice? This is by design, let's +have a look at the call stack of fsm_list::start() in main.cpp: + + FsmList::start() + Motor::set_initial_state() + Motor::current_state = Stopped + Elevator::set_initial_state() + Elevator::current_state = Idle + Motor::enter() + Motor:Stopped->entry() + cout << "Motor: stopped" <-- HERE + Motor::direction = 0 + Elevator::enter() + Elevator:Idle->entry() + send_event(MotorStop) + Motor::react(MotorStop) + Motor:Stopped->transit + Motor:Stopped->exit() + Motor::current_state = Stopped + Motor:Stopped->entry() + cout << "Motor: stopped" <-- HERE + Motor::direction = 0 + Elevator::react(MotorStop) + +If we really had to work around this, we could either: + + 1. Change the initialization (bad design practice!) in main.cpp: + + - fsm_list::start(); + + fsm_list::set_initial_state(); + + Elevator::enter(); + + + 2. Modify the Motor:Stopped->entry() function in motor.cpp: + + class Stopped : public Motor { + void entry() override { + + if(direction == 0) + + return; + cout << "Motor: stopped" << endl; + direction = 0; + }; diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/elevator b/device/gxx-linux/tinyfsm-master/examples/elevator/elevator new file mode 100644 index 0000000000000000000000000000000000000000..7634398aa6c6ef1a1316dda055c19b5b9efdc458 GIT binary patch literal 17368 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 literal 0 HcmV?d00001 diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.cpp b/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.cpp new file mode 100644 index 0000000..6e792f6 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.cpp @@ -0,0 +1,115 @@ +#include + +#include "elevator.hpp" +#include "fsmlist.hpp" + +#include + +class Idle; // forward declaration + + +// ---------------------------------------------------------------------------- +// Transition functions +// + +static void CallMaintenance() { + std::cout << "*** calling maintenance ***" << std::endl; +} + +static void CallFirefighters() { + std::cout << "*** calling firefighters ***" << std::endl; +} + + +// ---------------------------------------------------------------------------- +// State: Panic +// + +class Panic +: public Elevator +{ + void entry() override { + send_event(MotorStop()); + } +}; + + +// ---------------------------------------------------------------------------- +// State: Moving +// + +class Moving +: public Elevator +{ + void react(FloorSensor const & e) override { + int floor_expected = current_floor + Motor::getDirection(); + if(floor_expected != e.floor) + { + std::cout << "Floor sensor defect (expected " << floor_expected << ", got " << e.floor << ")" << std::endl; + transit(CallMaintenance); + } + else + { + std::cout << "Reached floor " << e.floor << std::endl; + current_floor = e.floor; + if(e.floor == dest_floor) + transit(); + } + }; +}; + + +// ---------------------------------------------------------------------------- +// State: Idle +// + +class Idle +: public Elevator +{ + void entry() override { + send_event(MotorStop()); + } + + void react(Call const & e) override { + dest_floor = e.floor; + + if(dest_floor == current_floor) + return; + + /* lambda function used for transition action */ + auto action = [] { + if(dest_floor > current_floor) + send_event(MotorUp()); + else if(dest_floor < current_floor) + send_event(MotorDown()); + }; + + transit(action); + }; +}; + + +// ---------------------------------------------------------------------------- +// Base state: default implementations +// + +void Elevator::react(Call const &) { + std::cout << "Call event ignored" << std::endl; +} + +void Elevator::react(FloorSensor const &) { + std::cout << "FloorSensor event ignored" << std::endl; +} + +void Elevator::react(Alarm const &) { + transit(CallFirefighters); +} + +int Elevator::current_floor = Elevator::initial_floor; +int Elevator::dest_floor = Elevator::initial_floor; + + +// ---------------------------------------------------------------------------- +// Initial state definition +// +FSM_INITIAL_STATE(Elevator, Idle) diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.d b/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.d new file mode 100644 index 0000000..873085f --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.d @@ -0,0 +1,2 @@ +elevator.o: elevator.cpp ../../include/tinyfsm.hpp elevator.hpp \ + fsmlist.hpp motor.hpp diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.hpp b/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.hpp new file mode 100644 index 0000000..be3d005 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.hpp @@ -0,0 +1,55 @@ +#ifndef ELEVATOR_HPP_INCLUDED +#define ELEVATOR_HPP_INCLUDED + +#include + + +// ---------------------------------------------------------------------------- +// Event declarations +// + +struct FloorEvent : tinyfsm::Event +{ + int floor; +}; + +struct Call : FloorEvent { }; +struct FloorSensor : FloorEvent { }; +struct Alarm : tinyfsm::Event { }; + + + +// ---------------------------------------------------------------------------- +// Elevator (FSM base class) declaration +// + +class Elevator +: public tinyfsm::Fsm +{ + /* NOTE: react(), entry() and exit() functions need to be accessible + * from tinyfsm::Fsm class. You might as well declare friendship to + * tinyfsm::Fsm, and make these functions private: + * + * friend class Fsm; + */ +public: + + /* default reaction for unhandled events */ + void react(tinyfsm::Event const &) { }; + + virtual void react(Call const &); + virtual void react(FloorSensor const &); + void react(Alarm const &); + + virtual void entry(void) { }; /* entry actions in some states */ + void exit(void) { }; /* no exit actions at all */ + +protected: + + static constexpr int initial_floor = 0; + static int current_floor; + static int dest_floor; +}; + + +#endif diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.o b/device/gxx-linux/tinyfsm-master/examples/elevator/elevator.o new file mode 100644 index 0000000000000000000000000000000000000000..710d28dfdc93d8d61f5f11b0820bac65c1e99478 GIT binary patch literal 13416 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 + +#include "elevator.hpp" +#include "motor.hpp" + +using fsm_list = tinyfsm::FsmList; + +/** dispatch event to both "Motor" and "Elevator" */ +template +void send_event(E const & event) +{ + fsm_list::template dispatch(event); +} + + +#endif diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/main.cpp b/device/gxx-linux/tinyfsm-master/examples/elevator/main.cpp new file mode 100644 index 0000000..4657015 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/elevator/main.cpp @@ -0,0 +1,40 @@ +#include "fsmlist.hpp" + +#include + + +int main() +{ + fsm_list::start(); + + Call call; + FloorSensor sensor; + + while(1) + { + char c; + + std::cout << "c=Call, f=FloorSensor, a=Alarm, q=Quit ? "; + std::cin >> c; + switch(c) { + case 'c': + std::cout << "Floor ? "; + std::cin >> call.floor; + send_event(call); + break; + case 'f': + std::cout << "Floor ? "; + std::cin >> sensor.floor; + send_event(sensor); + break; + case 'a': + send_event(Alarm()); + break; + case 'q': + std::cout << "Thanks for playing!" << std::endl; + return 0; + default: + std::cout << "Invalid input" << std::endl; + }; + } +} diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/main.d b/device/gxx-linux/tinyfsm-master/examples/elevator/main.d new file mode 100644 index 0000000..a8fba41 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/elevator/main.d @@ -0,0 +1,2 @@ +main.o: main.cpp fsmlist.hpp ../../include/tinyfsm.hpp elevator.hpp \ + motor.hpp diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/main.o b/device/gxx-linux/tinyfsm-master/examples/elevator/main.o new file mode 100644 index 0000000000000000000000000000000000000000..9985e07a51599e069cb394cf2c45cabbea70da84 GIT binary patch literal 4856 zcmb`LUu+ab7{F({1q&_ZPx%kFTd0brTv|(^8XNA~9`!;&>>Y^_l4ZNS(v`d0>+Y7c z)&z|_@=!w6ng9Xyfs&Z`V#LH4G$i_8Q%&O$% zOkA0$B4l(WT(=ICOss}>vV@$xZK@M%K+kO^IWQl?D|bve3GFB$;hX|jEnFJeIeDmr z^~?PJE$ENIHLb3`IHj(-h`!V6I?z{Aed<``nVJ*IKv*S-Eec8099IUkg(NXW zLNE`_`TN}5nwoKC;2hZ2Tu}z5@6IJ)4%CLn_HAG9o{2{$ZXIZwxNWviQzrY^jOq;&l7to&_ z`P{E@Imuy-U8w7nTE*%?+tHcwaIOTN&5nF|p^eTvjP-`)@WpIxH&Us3t*>=g%C?<& zGUM7#y=JsVQihYR*9KZ&9JD-br$*>=R1*D0=7_8H*^ZV?8N*iQa4m^tjv6VeSFI=YjMwG6+DWGN){Bu5M^Nj$9IMl;rN=B0H<{T zoz4kOK~z%aE5aT29!McasuDj7>Rf#LLXOW>`UZ1LzxD00()SA1T@mJsbwu&)gX&P> z8%cMS6fTn=XK8-J3O*`XD)jQIN`ylyk6~VXbOHobg-Xk^5x@#zUHCdQ0Y5L)hgZA@ zIN#G^tRn$@Fo3@oz<&UKURXz-_iljwc9?3h@i+ne!vKCMfL{yXHv@Pnlz3TTnaOhG zFoyz38&)P{X0xPji0GYNFSJFvbln~7(PKJ3B6Yn)e>v`TwdlHKTN%rP?%o}ql^O1H z(@neFbgU(sN**;l+le;rFb5qcnelYjGrXjp^_(d6ZZaVfhS_G?aBj&Fn)legyPNcM z%wZWRKScCsfw7qGVeIFF2aGM{#^PRMquFmby5|^{=f=!vv>RAckKtOTZo8h7G}19M zp-1D*`o7&Jor(i?_jk0IV?s|ffa`X>JKm)GWk_avQx9_IdFS1+6miROqumy&^Mz=J z;hA2vdv`Pam{2pX#j;%;CXn0~gMzj<`jw1Jyn}MR*R^%{+VrN9MAywBLx60P%zGVU#0hYrf&egLEsGn=P?oC zHw^{zKI*IV&d>8|iFYv@>XTpZ6Kfs6A^F^=P`W;!-Q0evWZD?*{_cn2yb7Oy}|Od_}oT@A-A%{AUzV>&iBna<-s#rl7< zmXDwFe;AkJmq8s-kk|Suy;m?UuU8%8a^8Bz<-FS%m-B`NUMuA7U|i0NKVDH}eo%ge$ z@%7L?F2v!g0vvyB@bC0S_Fw_y-0mfbb9)kUhtrTz8X za*`<{gcOVo#~aKtgr5lAa2#Wp8ioSDCq<5Yj9lO_f0P#ggoPX%M}P2XuLsr=r2{Vf)h&lK@6RKuv0+gk1Xtif)_@&B z_OSVg-+X*5`+qAi!JWJ!)q_9d{=EMy^Ow!D3=DBY*7Evud>xcx>-Qa7KRz#9Km2Qp z`}6g~@yNLWk>41+z&6$jVDSH*0{=z8 +#include "motor.hpp" +#include + + +// ---------------------------------------------------------------------------- +// Motor states +// + +class Stopped +: public Motor +{ + void entry() override { + std::cout << "Motor: stopped" << std::endl; + direction = 0; + }; +}; + +class Up +: public Motor +{ + void entry() override { + std::cout << "Motor: moving up" << std::endl; + direction = 1; + }; +}; + +class Down +: public Motor +{ + void entry() override { + std::cout << "Motor: moving down" << std::endl; + direction = -1; + }; +}; + + +// ---------------------------------------------------------------------------- +// Base State: default implementations +// + +void Motor::react(MotorStop const &) { + transit(); +} + +void Motor::react(MotorUp const &) { + transit(); +} + +void Motor::react(MotorDown const &) { + transit(); +} + +int Motor::direction{0}; + + +// ---------------------------------------------------------------------------- +// Initial state definition +// +FSM_INITIAL_STATE(Motor, Stopped) diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/motor.d b/device/gxx-linux/tinyfsm-master/examples/elevator/motor.d new file mode 100644 index 0000000..02e7e75 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/elevator/motor.d @@ -0,0 +1 @@ +motor.o: motor.cpp ../../include/tinyfsm.hpp motor.hpp diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/motor.hpp b/device/gxx-linux/tinyfsm-master/examples/elevator/motor.hpp new file mode 100644 index 0000000..7d2447c --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/examples/elevator/motor.hpp @@ -0,0 +1,50 @@ +#ifndef MOTOR_HPP_INCLUDED +#define MOTOR_HPP_INCLUDED + +#include + + +// ---------------------------------------------------------------------------- +// Event declarations +// + +struct MotorUp : tinyfsm::Event { }; +struct MotorDown : tinyfsm::Event { }; +struct MotorStop : tinyfsm::Event { }; + + +// ---------------------------------------------------------------------------- +// Motor (FSM base class) declaration +// +class Motor +: public tinyfsm::Fsm +{ + /* NOTE: react(), entry() and exit() functions need to be accessible + * from tinyfsm::Fsm class. You might as well declare friendship to + * tinyfsm::Fsm, and make these functions private: + * + * friend class Fsm; + */ +public: + + /* default reaction for unhandled events */ + void react(tinyfsm::Event const &) { }; + + /* non-virtual declaration: reactions are the same for all states */ + void react(MotorUp const &); + void react(MotorDown const &); + void react(MotorStop const &); + + virtual void entry(void) = 0; /* pure virtual: enforce implementation in all states */ + void exit(void) { }; /* no exit actions at all */ + +protected: + + static int direction; + +public: + static int getDirection() { return direction; } +}; + + +#endif diff --git a/device/gxx-linux/tinyfsm-master/examples/elevator/motor.o b/device/gxx-linux/tinyfsm-master/examples/elevator/motor.o new file mode 100644 index 0000000000000000000000000000000000000000..415a0205bbdd55d26c1bbd99ead4bf8bdc989790 GIT binary patch literal 8600 zcmd5>U2Ggz6~609!%s?ZlU9U=rfcJZLz}^F?AVC_trKt3C9bJrCxn1B8t+b%Rrkl5 z9S56$h4&-eNz#vUc`xZtarrUQ`?&l#>munPE)SFbG?zz6KarN#N#VItRO$}t zhbi`dg>87jAMalJ-7D}1A9p=+x-jl>z!1uzqg}wX8?V_^v2Djy5A)|CuH+K zlV{sWJ3dluwlCIO=Zh=LDht%w-)srgN!rWHQBA26$BrE-j?P9)^{`c(_7D1F2M+B| z3wl4H^M!AnQrlMd74|;(xZX2+ctjJ>Gdl;b4O}mL`Okmai7NKgGzuhn?Pt?w+Pfso zuP}d*pjB?izJ&mLQJ2!aEZEN+*sB&+r1~w!O3*Vqi`TYY_l~|aKwbWW?lU*{DcWah zoBG$k`x*%F)D9O+_{VZ^cPLNcgV`)2G{Ik5k_-oi3h~=&2`dNY_2JKLUeh~Y=u>BWO^RE3MZ4uY}jOO4a;ErweY>xdo!iS7=x`*S}G(OBVr37zi zyx51Y5&jUJQxQ3@s)-lBUtL~SBdaPnG53|DGjl=ESy>7yL2zz*@mC0MtlL1?Lu$x#=LNx9hEXLe=@FPcKhKtt4J6U(~G=)%FS+7LrD%vXG3AS1*Kd zki=m<=~Sxa@+ra&E`^Kz%_(*3T!`j@79=Yj9dY&C+CrSb=Ts>^0 z1Ja8&zmQDV+ns<`C7P&E^RaO^KCAJd)@cV9LRzFq1wnN+3~0($^=?=^qdP)w>tZy{yY# z!e#7mC+h-y((qs8GU7_#0LeT*X5nJ9S^s<4xAzX%tpBF{|3m-ryIf=|^KaUJQ2m$v zZ_mG+UwgfzpV$wwMi_&+?j;!%=@Bkt9cK(&)*b$j8o2Bw_&0GmM_6CekDMc%uVaQE zDHaHqu?PkYe3rC~N7{fR54!N<1}^QeH}jZ@n|a2>%{(CU_5k@YZ>cga;O1@g8{ARg z=B@MF20p-LsC5gM^ZauQmwoV>g-bu)GVsiN`kl3A5-us9t`DicAf-5Jgg(8D66M#z zBvk%Vr=$EX>Rb1fY)kg`kZqHfSob1fG}DbBPU!nd3gPt{gmE0MF@TPs$#1l)VFO)| zcXR)(BKsOo9o`S$yiD9bTL#&^M_~HQ4rebDjw_QDGj4YWy?92v+tZRU!lhv|C+YRV zkK1}yvdfA6Fz$~NzuTHwQb)V=NtU&1Qf)VzbRATFtDQvtiTTq9XqBrkaNnW}!Siw0 zjFf*qZqv$tAo3y|BG*@$5_^|3aDeJK=aLIW=kezpeB=Y+iO%Dnb?}jYgeN+WUvuzr zj}e~eJibh?Iez2_;fc=UOP(_MxaSB@bRPc)+<&>pVE%DW6`trkzT`tQKJvQoMCb8e z=J+Nb?+f9H&g0*7@Mj(TB4L!``@T@TN*Lt1RCWJKTmkTl8(2vI*1zYD--2@z%pbl5 z%6!Vb0$+|`Vt;Ab#yo1uhz&nQt?-%0H{W$|WcMFu0zS8!FEiM2Ah{Y{%_4X*fCIjPG&$N2H}T6lv0k}!nwto`%uJ>nBZ3;x06n*U!p;^S+V z9seJMx#ItGi}C-S6aSVYK5~T}{{Y2t#eaW`@khzdHU8U<`1l5C$A5wN!0h>#Pr_nP zCR*(J4dSD#d3;%Crg!5@9sAtX|MwmJFA_=Oi{CeM;_u=8Bz6){_)>p8C;lM*IZPsa z?B8K}gfIACbK;L}G5$L_@kbr;M;!4n@8lx$t%a)U8II4>2uKTTA)<$J_+Mjw?@M-; zC;XWleuMd(hEuW;SNQn8i?W?(FEJl`))e81ZZhArLHR24ZCrSQe~ + * --------------------------------------------------------------------- + */ + +#ifndef TINYFSM_HPP_INCLUDED +#define TINYFSM_HPP_INCLUDED + +#ifndef TINYFSM_NOSTDLIB +#include +#endif + +// #include +// #define DBG(str) do { std::cerr << str << std::endl; } while( false ) +// DBG("*** dbg_example *** " << __PRETTY_FUNCTION__); + +namespace tinyfsm +{ + + // -------------------------------------------------------------------------- + + struct Event { }; + + // -------------------------------------------------------------------------- + +#ifdef TINYFSM_NOSTDLIB + // remove dependency on standard library (silent fail!). + // useful in conjunction with -nostdlib option, e.g. if your compiler + // does not provide a standard library. + // NOTE: this silently disables all static_assert() calls below! + template + struct is_same_fsm { static constexpr bool value = true; }; +#else + // check if both fsm and state class share same fsmtype + template + struct is_same_fsm : std::is_same< typename F::fsmtype, typename S::fsmtype > { }; +#endif + + template + struct _state_instance + { + using value_type = S; + using type = _state_instance; + static S value; + }; + + template + typename _state_instance::value_type _state_instance::value; + + // -------------------------------------------------------------------------- + + template + class Fsm + { + public: + + using fsmtype = Fsm; + using state_ptr_t = F *; + + static state_ptr_t current_state_ptr; + + // public, leaving ability to access state instance (e.g. on reset) + template + static constexpr S & state(void) { + static_assert(is_same_fsm::value, "accessing state of different state machine"); + return _state_instance::value; + } + + template + static constexpr bool is_in_state(void) { + static_assert(is_same_fsm::value, "accessing state of different state machine"); + return current_state_ptr == &_state_instance::value; + } + + /// state machine functions + public: + + // explicitely specialized in FSM_INITIAL_STATE macro + static void set_initial_state(); + + static void reset() { }; + + static void enter() { + current_state_ptr->entry(); + } + + static void start() { + set_initial_state(); + enter(); + } + + template + static void dispatch(E const & event) { + current_state_ptr->react(event); + } + + + /// state transition functions + protected: + + template + void transit(void) { + static_assert(is_same_fsm::value, "transit to different state machine"); + current_state_ptr->exit(); + current_state_ptr = &_state_instance::value; + current_state_ptr->entry(); + } + + template + void transit(ActionFunction action_function) { + static_assert(is_same_fsm::value, "transit to different state machine"); + current_state_ptr->exit(); + // NOTE: we get into deep trouble if the action_function sends a new event. + // TODO: implement a mechanism to check for reentrancy + action_function(); + current_state_ptr = &_state_instance::value; + current_state_ptr->entry(); + } + + template + void transit(ActionFunction action_function, ConditionFunction condition_function) { + if(condition_function()) { + transit(action_function); + } + } + }; + + template + typename Fsm::state_ptr_t Fsm::current_state_ptr; + + // -------------------------------------------------------------------------- + + template + struct FsmList; + + template<> struct FsmList<> { + static void set_initial_state() { } + static void reset() { } + static void enter() { } + template + static void dispatch(E const &) { } + }; + + template + struct FsmList + { + using fsmtype = Fsm; + + static void set_initial_state() { + fsmtype::set_initial_state(); + FsmList::set_initial_state(); + } + + static void reset() { + F::reset(); + FsmList::reset(); + } + + static void enter() { + fsmtype::enter(); + FsmList::enter(); + } + + static void start() { + set_initial_state(); + enter(); + } + + template + static void dispatch(E const & event) { + fsmtype::template dispatch(event); + FsmList::template dispatch(event); + } + }; + + // -------------------------------------------------------------------------- + + template struct StateList; + template<> struct StateList<> { + static void reset() { } + }; + template + struct StateList + { + static void reset() { + _state_instance::value = S(); + StateList::reset(); + } + }; + + // -------------------------------------------------------------------------- + + template + struct MooreMachine : tinyfsm::Fsm + { + virtual void entry(void) { }; /* entry actions in some states */ + void exit(void) { }; /* no exit actions */ + }; + + template + struct MealyMachine : tinyfsm::Fsm + { + // input actions are modeled in react(): + // - conditional dependent of event type or payload + // - transit<>(ActionFunction) + void entry(void) { }; /* no entry actions */ + void exit(void) { }; /* no exit actions */ + }; + +} /* namespace tinyfsm */ + + +#define FSM_INITIAL_STATE(_FSM, _STATE) \ +namespace tinyfsm { \ + template<> void Fsm< _FSM >::set_initial_state(void) { \ + current_state_ptr = &_state_instance< _STATE >::value; \ + } \ +} + +#endif /* TINYFSM_HPP_INCLUDED */ diff --git a/device/gxx-linux/tinyfsm-master/library.json b/device/gxx-linux/tinyfsm-master/library.json new file mode 100644 index 0000000..fab83b5 --- /dev/null +++ b/device/gxx-linux/tinyfsm-master/library.json @@ -0,0 +1,24 @@ +{ + "name": "tinyfsm", + "description": "A simple C++ finite state machine library", + "version": "0.3.2", + "repository": { + "type": "git", + "url": "https://dev.tty0.ch/tinyfsm.git" + }, + "homepage": "https://digint.ch/tinyfsm/", + "authors": { + "name": "Axel Burri", + "email": "axel@tty0.ch", + "url": "http://digint.ch", + "maintainer": true + }, + "license": "MIT", + "platforms": "*", + "frameworks": "*", + "build": { + "flags": [ + "-I include/" + ] + } +} diff --git a/device/gxx-linux/testusb/usb-rk3399/src/app.log b/device/gxx-linux/tinyfsm-master/tree.h similarity index 100% rename from device/gxx-linux/testusb/usb-rk3399/src/app.log rename to device/gxx-linux/tinyfsm-master/tree.h diff --git a/device/gxx-linux/usb/inc/usbdevice.h b/device/gxx-linux/usb/inc/usbdevice.h index 8fbd4d2..9baeb2e 100644 --- a/device/gxx-linux/usb/inc/usbdevice.h +++ b/device/gxx-linux/usb/inc/usbdevice.h @@ -1,4 +1,6 @@ + #pragma once + #include #include #include @@ -10,46 +12,25 @@ #include "buildconf.h" #include "usb_gadget.h" -#include "usb_io.h" -#include #include -class UsbDevice #ifdef ASYNC_EP - : public sane_cfg_provider +class async_scanner; #endif + +class UsbDevice { #ifdef ASYNC_EP - async_usb_gadget *usb_; - sane_cfg_mgr *cfg_; - uint32_t img_cnt_; - uint32_t scan_id_; - uint32_t dpi_; - uint32_t scan_cnt_; - uint32_t scan_err_; - std::string cfg_text_; - dyn_mem_ptr scan_over_pack_; - - dyn_mem_ptr unhandled_ep0(struct usb_functionfs_event* pev); - dyn_mem_ptr handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - - std::map dispatcher_; - dyn_mem_ptr handle_packet_heart_beat(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - dyn_mem_ptr handle_packet_invalid(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - dyn_mem_ptr handle_packet_get_setting(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - dyn_mem_ptr handle_packet_set_setting(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - - dyn_mem_ptr handle_packet_write_file(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); - dyn_mem_ptr handle_packet_read_file(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + async_scanner *ascan_; void do_system_command(const char* cmd); - void init(void); public: - void save_image(MemoryPtr data, bool img); - - virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; - virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + int start_scan(void); + int stop_scan(void); + int set_dpi(int *dpix, int* dpiy); + int set_scan_num(int num); + int set_img_receiver(void* api, void* param); #endif public: diff --git a/device/gxx-linux/usb/src/common/encrypt.cpp b/device/gxx-linux/usb/src/async_model/common/encrypt.cpp similarity index 100% rename from device/gxx-linux/usb/src/common/encrypt.cpp rename to device/gxx-linux/usb/src/async_model/common/encrypt.cpp diff --git a/device/gxx-linux/usb/src/common/encrypt.h b/device/gxx-linux/usb/src/async_model/common/encrypt.h similarity index 98% rename from device/gxx-linux/usb/src/common/encrypt.h rename to device/gxx-linux/usb/src/async_model/common/encrypt.h index 97d427f..5e64b9f 100644 --- a/device/gxx-linux/usb/src/common/encrypt.h +++ b/device/gxx-linux/usb/src/async_model/common/encrypt.h @@ -6,7 +6,7 @@ #include "referer.h" -#include "data.h" +#include "io/data.h" enum encryptor diff --git a/device/gxx-linux/usb/src/common/ipc_util.cpp b/device/gxx-linux/usb/src/async_model/common/ipc_util.cpp similarity index 100% rename from device/gxx-linux/usb/src/common/ipc_util.cpp rename to device/gxx-linux/usb/src/async_model/common/ipc_util.cpp diff --git a/device/gxx-linux/usb/src/common/ipc_util.h b/device/gxx-linux/usb/src/async_model/common/ipc_util.h similarity index 100% rename from device/gxx-linux/usb/src/common/ipc_util.h rename to device/gxx-linux/usb/src/async_model/common/ipc_util.h diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/json/cJSON.c b/device/gxx-linux/usb/src/async_model/common/json/cJSON.c similarity index 97% rename from device/gxx-linux/testusb/usb-rk3399/src/common/json/cJSON.c rename to device/gxx-linux/usb/src/async_model/common/json/cJSON.c index cd60134..594376b 100644 --- a/device/gxx-linux/testusb/usb-rk3399/src/common/json/cJSON.c +++ b/device/gxx-linux/usb/src/async_model/common/json/cJSON.c @@ -776,19 +776,19 @@ cJSON *cJSON_Duplicate(cJSON *item,int recurse) return newitem; } -void cJSON_Minify(char *json) +void cJSON_Minify(char *gb_json) { - char *into=json; - while (*json) + char *into=gb_json; + while (*gb_json) { - if (*json==' ') json++; - else if (*json=='\t') json++; /* Whitespace characters. */ - else if (*json=='\r') json++; - else if (*json=='\n') json++; - else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ - else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ - else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ - else *into++=*json++; /* All other characters. */ + if (*gb_json==' ') gb_json++; + else if (*gb_json=='\t') gb_json++; /* Whitespace characters. */ + else if (*gb_json=='\r') gb_json++; + else if (*gb_json=='\n') gb_json++; + else if (*gb_json=='/' && gb_json[1]=='/') while (*gb_json && *gb_json!='\n') gb_json++; /* double-slash comments, to end of line. */ + else if (*gb_json=='/' && gb_json[1]=='*') {while (*gb_json && !(*gb_json=='*' && gb_json[1]=='/')) gb_json++;gb_json+=2;} /* multiline comments. */ + else if (*gb_json=='\"'){*into++=*gb_json++;while (*gb_json && *gb_json!='\"'){if (*gb_json=='\\') *into++=*gb_json++;*into++=*gb_json++;}*into++=*gb_json++;} /* string literals, which are \" sensitive. */ + else *into++=*gb_json++; /* All other characters. */ } *into=0; /* and null-terminate. */ } diff --git a/device/gxx-linux/usb/src/common/json/cJSON.h b/device/gxx-linux/usb/src/async_model/common/json/cJSON.h similarity index 99% rename from device/gxx-linux/usb/src/common/json/cJSON.h rename to device/gxx-linux/usb/src/async_model/common/json/cJSON.h index 913bc1e..9fdbf9b 100644 --- a/device/gxx-linux/usb/src/common/json/cJSON.h +++ b/device/gxx-linux/usb/src/async_model/common/json/cJSON.h @@ -133,7 +133,7 @@ The item->next and ->prev pointers are always zero on return from Duplicate. */ /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); -extern void cJSON_Minify(char *json); +extern void cJSON_Minify(char *gb_json); // convert e681a2 to \u6062, call 'free' to free the returned value extern char* cJSON_utf8_2_unic(const char* utf8); diff --git a/device/gxx-linux/usb/src/common/json/json.cpp b/device/gxx-linux/usb/src/async_model/common/json/gb_json.cpp similarity index 72% rename from device/gxx-linux/usb/src/common/json/json.cpp rename to device/gxx-linux/usb/src/async_model/common/json/gb_json.cpp index e3b4b3a..e8610c8 100644 --- a/device/gxx-linux/usb/src/common/json/json.cpp +++ b/device/gxx-linux/usb/src/async_model/common/json/gb_json.cpp @@ -1,5 +1,5 @@ -#include "json.h" +#include "gb_json.h" #include "cJSON.h" #include #include @@ -81,72 +81,72 @@ namespace special_char_trans } -json::json(char* json_txt) : type_(VAL_TYPE_OBJECT), key_(""), strval_(""), cur_child_(-1) +gb_json::gb_json(char* json_txt) : type_(VAL_TYPE_OBJECT), key_(""), strval_(""), cur_child_(-1) { simple_val_.dval = .0f; if(json_txt) attach_text(json_txt); } -json::json(const char* key, bool val) : type_(VAL_TYPE_BOOL), key_(key ? key : ""), strval_(""), cur_child_(-1) +gb_json::gb_json(const char* key, bool val) : type_(VAL_TYPE_BOOL), key_(key ? key : ""), strval_(""), cur_child_(-1) { simple_val_.bval = val; } -json::json(const char* key, int val) : type_(VAL_TYPE_INT), key_(key ? key : ""), strval_(""), cur_child_(-1) +gb_json::gb_json(const char* key, int val) : type_(VAL_TYPE_INT), key_(key ? key : ""), strval_(""), cur_child_(-1) { simple_val_.nval = val; } -json::json(const char* key, double val) : type_(VAL_TYPE_FLOAT), key_(key ? key : ""), strval_(""), cur_child_(-1) +gb_json::gb_json(const char* key, double val) : type_(VAL_TYPE_FLOAT), key_(key ? key : ""), strval_(""), cur_child_(-1) { simple_val_.dval = val; } -json::json(const char* key, const char* val) : type_(VAL_TYPE_STRING), key_(key ? key : ""), strval_(val ? val : ""), cur_child_(-1) +gb_json::gb_json(const char* key, const char* val) : type_(VAL_TYPE_STRING), key_(key ? key : ""), strval_(val ? val : ""), cur_child_(-1) {} -json::~json() +gb_json::~gb_json() { clear(); } -std::string json::object_key(json* jsn) +std::string gb_json::object_key(gb_json* jsn) { return "\"" + jsn->key() + "\":"; } -std::string json::array_key(json* jsn) +std::string gb_json::array_key(gb_json* jsn) { return ""; } -void json::from_cjson(cJSON* cj) +void gb_json::from_cjson(cJSON* cj) { key_ = cj && cj->string ? cj->string : ""; while (cj) { - json* child = nullptr; + gb_json* child = nullptr; if (cj->type == cJSON_True) { - child = new json(cj->string, true); + child = new gb_json(cj->string, true); } else if(cj->type == cJSON_False) { - child = new json(cj->string, false); + child = new gb_json(cj->string, false); } else if (cj->type == cJSON_Number) { if (cj->valuedouble - (int)cj->valuedouble < .00001) { - child = new json(cj->string, cj->valueint); + child = new gb_json(cj->string, cj->valueint); } else { - child = new json(cj->string, cj->valuedouble); + child = new gb_json(cj->string, cj->valuedouble); } } else if (cj->type == cJSON_String) { - child = new json(cj->string, cj->valuestring); + child = new gb_json(cj->string, cj->valuestring); } else if (cj->type == cJSON_Object || cj->type == cJSON_Array) { - child = new json(); + child = new gb_json(); child->from_cjson(cj->child); child->key_ = cj->string ? cj->string : ""; } @@ -156,7 +156,7 @@ void json::from_cjson(cJSON* cj) if (arr_val_.size() == 1 && arr_val_[0]->arr_val_.size() == 0) { - json* child = arr_val_[0]; + gb_json* child = arr_val_[0]; if (!child->key_.empty()) // array { @@ -177,9 +177,9 @@ void json::from_cjson(cJSON* cj) type_ = arr_val_[0]->key().empty() ? VAL_TYPE_ARRAY : VAL_TYPE_OBJECT; } } -json* json::find_child(const char* key, bool remove) +gb_json* gb_json::find_child(const char* key, bool remove) { - json* ret = nullptr; + gb_json* ret = nullptr; if (type_ == VAL_TYPE_OBJECT) { @@ -201,7 +201,7 @@ json* json::find_child(const char* key, bool remove) return ret; } -bool json::attach_text(char* json_txt) +bool gb_json::attach_text(char* json_txt) { clear(); @@ -220,7 +220,7 @@ bool json::attach_text(char* json_txt) return false; } -void json::clear(bool as_array) +void gb_json::clear(bool as_array) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) { @@ -234,7 +234,7 @@ void json::clear(bool as_array) arr_val_.clear(); cur_child_ = -1; } -std::string json::to_string(void) +std::string gb_json::to_string(void) { if (type_ == VAL_TYPE_NULL) return ""; @@ -255,7 +255,7 @@ std::string json::to_string(void) return "\"" + r + "\""; } - std::string(*k)(json*) = type_ == VAL_TYPE_OBJECT ? json::object_key : json::array_key; + std::string(*k)(gb_json*) = type_ == VAL_TYPE_OBJECT ? gb_json::object_key : gb_json::array_key; std::string str(type_ == VAL_TYPE_OBJECT ? "{" : "["); if (arr_val_.size()) @@ -269,15 +269,15 @@ std::string json::to_string(void) return str; } -std::string& json::key(void) +std::string& gb_json::key(void) { return key_; } -bool json::is_array(void) +bool gb_json::is_array(void) { return type_ == VAL_TYPE_ARRAY; } -bool json::is_leaf_node(void) +bool gb_json::is_leaf_node(void) { return type_ == VAL_TYPE_BOOL || type_ == VAL_TYPE_INT || @@ -285,10 +285,10 @@ bool json::is_leaf_node(void) type_ == VAL_TYPE_STRING; } -bool json::get_value(const char* key, bool& val) +bool gb_json::get_value(const char* key, bool& val) { bool ret = false; - json* child = find_child(key); + gb_json* child = find_child(key); if (child) { @@ -307,10 +307,10 @@ bool json::get_value(const char* key, bool& val) return ret; } -bool json::get_value(const char* key, int& val) +bool gb_json::get_value(const char* key, int& val) { bool ret = false; - json* child = find_child(key); + gb_json* child = find_child(key); if (child) { @@ -329,10 +329,10 @@ bool json::get_value(const char* key, int& val) return ret; } -bool json::get_value(const char* key, double& val) +bool gb_json::get_value(const char* key, double& val) { bool ret = false; - json* child = find_child(key); + gb_json* child = find_child(key); if (child) { @@ -349,12 +349,21 @@ bool json::get_value(const char* key, double& val) ret = true; } + // added on 2023-04-27: for cJSON consider both int and float as CJSON_Number, we consider int if the value is just an integer + if(!ret) + { + int v = 0; + ret = get_value(key, v); + if(ret) + val = v; + } + return ret; } -bool json::get_value(const char* key, std::string& val) +bool gb_json::get_value(const char* key, std::string& val) { bool ret = false; - json* child = find_child(key); + gb_json* child = find_child(key); if (child) { @@ -373,10 +382,10 @@ bool json::get_value(const char* key, std::string& val) return ret; } -bool json::get_value(const char* key, json*& val) +bool gb_json::get_value(const char* key, gb_json*& val) { bool ret = false; - json *child = find_child(key); + gb_json *child = find_child(key); if (child) { @@ -394,14 +403,14 @@ bool json::get_value(const char* key, json*& val) return ret; } -size_t json::children(void) +size_t gb_json::children(void) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) return arr_val_.size(); else return -1; } -json* json::child(size_t ind) +gb_json* gb_json::child(size_t ind) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) { @@ -415,7 +424,7 @@ json* json::child(size_t ind) return nullptr; } -json* json::first_child(void) +gb_json* gb_json::first_child(void) { if (type_ == VAL_TYPE_OBJECT || type_ == VAL_TYPE_ARRAY) { @@ -430,7 +439,7 @@ json* json::first_child(void) return nullptr; } -json* json::next_child(void) +gb_json* gb_json::next_child(void) { if (type_ == VAL_TYPE_OBJECT || type_ == VAL_TYPE_ARRAY) { @@ -445,12 +454,12 @@ json* json::next_child(void) return nullptr; } -bool json::set_value(const char* key, bool val) +bool gb_json::set_value(const char* key, bool val) { if (type_ != VAL_TYPE_OBJECT) return false; - json* child = find_child(key); + gb_json* child = find_child(key); if (child) { @@ -462,18 +471,18 @@ bool json::set_value(const char* key, bool val) } else { - child = new json(key, val); + child = new gb_json(key, val); arr_val_.push_back(child); } return true; } -bool json::set_value(const char* key, int val) +bool gb_json::set_value(const char* key, int val) { if (type_ != VAL_TYPE_OBJECT) return false; - json* child = find_child(key); + gb_json* child = find_child(key); if (child) { @@ -485,18 +494,18 @@ bool json::set_value(const char* key, int val) } else { - child = new json(key, val); + child = new gb_json(key, val); arr_val_.push_back(child); } return true; } -bool json::set_value(const char* key, double val) +bool gb_json::set_value(const char* key, double val) { if (type_ != VAL_TYPE_OBJECT) return false; - json* child = find_child(key); + gb_json* child = find_child(key); if (child) { @@ -508,18 +517,18 @@ bool json::set_value(const char* key, double val) } else { - child = new json(key, val); + child = new gb_json(key, val); arr_val_.push_back(child); } return true; } -bool json::set_value(const char* key, const char* val) +bool gb_json::set_value(const char* key, const char* val) { if (type_ != VAL_TYPE_OBJECT) return false; - json* child = find_child(key); + gb_json* child = find_child(key); if (child) { @@ -531,13 +540,13 @@ bool json::set_value(const char* key, const char* val) } else { - child = new json(key, val); + child = new gb_json(key, val); arr_val_.push_back(child); } return true; } -bool json::set_value(const char* key, json* val) +bool gb_json::set_value(const char* key, gb_json* val) { if (type_ != VAL_TYPE_OBJECT) return false; @@ -560,47 +569,47 @@ bool json::set_value(const char* key, json* val) return true; } -json& json::operator+=(bool val) +gb_json& gb_json::operator+=(bool val) { if (type_ == VAL_TYPE_ARRAY) { - json* child = new json(nullptr, val); + gb_json* child = new gb_json(nullptr, val); arr_val_.push_back(child); } return *this; } -json& json::operator+=(int val) +gb_json& gb_json::operator+=(int val) { if (type_ == VAL_TYPE_ARRAY) { - json* child = new json(nullptr, val); + gb_json* child = new gb_json(nullptr, val); arr_val_.push_back(child); } return *this; } -json& json::operator+=(double val) +gb_json& gb_json::operator+=(double val) { if (type_ == VAL_TYPE_ARRAY) { - json* child = new json(nullptr, val); + gb_json* child = new gb_json(nullptr, val); arr_val_.push_back(child); } return *this; } -json& json::operator+=(const char* val) +gb_json& gb_json::operator+=(const char* val) { if (type_ == VAL_TYPE_ARRAY) { - json* child = new json(nullptr, val); + gb_json* child = new gb_json(nullptr, val); arr_val_.push_back(child); } return *this; } -json& json::operator+=(json* val) +gb_json& gb_json::operator+=(gb_json* val) { if (type_ == VAL_TYPE_ARRAY) { @@ -611,15 +620,15 @@ json& json::operator+=(json* val) return *this; } -json& json::operator-=(int ind) +gb_json& gb_json::operator-=(int ind) { remove(ind); return *this; } -bool json::remove(const char* key) +bool gb_json::remove(const char* key) { - json* child = find_child(key, true); + gb_json* child = find_child(key, true); if (child) { @@ -631,7 +640,7 @@ bool json::remove(const char* key) return false; } } -bool json::remove(json* child) +bool gb_json::remove(gb_json* child) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) { @@ -649,7 +658,7 @@ bool json::remove(json* child) return false; } -bool json::remove(int ind) +bool gb_json::remove(int ind) { bool ret = false; @@ -666,7 +675,7 @@ bool json::remove(int ind) return ret; } -int json::index(json* child) +int gb_json::index(gb_json* child) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) { @@ -679,7 +688,7 @@ int json::index(json* child) return -1; } -int json::index_move_to(json* child, int ind) +int gb_json::index_move_to(gb_json* child, int ind) { int i = index(child); @@ -696,7 +705,7 @@ int json::index_move_to(json* child, int ind) return ind; } -bool json::value(bool& val) +bool gb_json::value(bool& val) { bool ret = false; @@ -708,7 +717,7 @@ bool json::value(bool& val) return ret; } -bool json::value(int& val) +bool gb_json::value(int& val) { bool ret = false; @@ -720,7 +729,7 @@ bool json::value(int& val) return ret; } -bool json::value(double& val) +bool gb_json::value(double& val) { bool ret = false; @@ -732,7 +741,7 @@ bool json::value(double& val) return ret; } -bool json::value(std::string& val) +bool gb_json::value(std::string& val) { bool ret = false; @@ -744,7 +753,7 @@ bool json::value(std::string& val) return ret; } -json& json::operator=(bool val) +gb_json& gb_json::operator=(bool val) { if (is_leaf_node()) { @@ -754,7 +763,7 @@ json& json::operator=(bool val) return *this; } -json& json::operator=(int val) +gb_json& gb_json::operator=(int val) { if (is_leaf_node()) { @@ -764,7 +773,7 @@ json& json::operator=(int val) return *this; } -json& json::operator=(double val) +gb_json& gb_json::operator=(double val) { if (is_leaf_node()) { @@ -774,7 +783,7 @@ json& json::operator=(double val) return *this; } -json& json::operator=(const char* val) +gb_json& gb_json::operator=(const char* val) { if (is_leaf_node()) { diff --git a/device/gxx-linux/usb/src/common/json/json.h b/device/gxx-linux/usb/src/async_model/common/json/gb_json.h similarity index 66% rename from device/gxx-linux/usb/src/common/json/json.h rename to device/gxx-linux/usb/src/async_model/common/json/gb_json.h index 3adff81..e22e74e 100644 --- a/device/gxx-linux/usb/src/common/json/json.h +++ b/device/gxx-linux/usb/src/async_model/common/json/gb_json.h @@ -48,7 +48,7 @@ public: struct cJSON; -class json : public refer +class gb_json : public refer { enum val_type { @@ -69,24 +69,24 @@ class json : public refer double dval; }simple_val_; std::string strval_; - std::vector arr_val_; + std::vector arr_val_; size_t cur_child_; - static std::string object_key(json* jsn); - static std::string array_key(json* jsn); + static std::string object_key(gb_json* jsn); + static std::string array_key(gb_json* jsn); void from_cjson(cJSON* cj); - json* find_child(const char* key, bool remove = false); + gb_json* find_child(const char* key, bool remove = false); public: - json(char* json_txt = 0); + gb_json(char* json_txt = 0); protected: - json(const char* key, bool val); - json(const char* key, int val); - json(const char* key, double val); - json(const char* key, const char* val); - ~json(); + gb_json(const char* key, bool val); + gb_json(const char* key, int val); + gb_json(const char* key, double val); + gb_json(const char* key, const char* val); + ~gb_json(); public: // parse/un-parse ... @@ -104,45 +104,45 @@ public: bool get_value(const char* key, int& val); bool get_value(const char* key, double& val); bool get_value(const char* key, std::string& val); - bool get_value(const char* key, json*& val); + bool get_value(const char* key, gb_json*& val); // enumeration ... size_t children(void); // return children count if was object or array, or else -1 returned - json* child(size_t ind); - json* first_child(void); - json* next_child(void); + gb_json* child(size_t ind); + gb_json* first_child(void); + gb_json* next_child(void); // change the item matching 'key', otherwise add a new item bool set_value(const char* key, bool val); bool set_value(const char* key, int val); bool set_value(const char* key, double val); bool set_value(const char* key, const char* val); - bool set_value(const char* key, json* val); + bool set_value(const char* key, gb_json* val); // operator+= only for array - json& operator+=(bool val); - json& operator+=(int val); - json& operator+=(double val); - json& operator+=(const char* val); - json& operator+=(json* val); + gb_json& operator+=(bool val); + gb_json& operator+=(int val); + gb_json& operator+=(double val); + gb_json& operator+=(const char* val); + gb_json& operator+=(gb_json* val); // remove item - json& operator-=(int ind); + gb_json& operator-=(int ind); bool remove(const char* key); - bool remove(json* child); + bool remove(gb_json* child); bool remove(int ind); // position management - int index(json* child); - int index_move_to(json* child, int ind); + int index(gb_json* child); + int index_move_to(gb_json* child, int ind); // leaf node value ... bool value(bool& val); bool value(int& val); bool value(double& val); bool value(std::string& val); - json& operator=(bool val); - json& operator=(int val); - json& operator=(double val); - json& operator=(const char* val); + gb_json& operator=(bool val); + gb_json& operator=(int val); + gb_json& operator=(double val); + gb_json& operator=(const char* val); }; diff --git a/device/gxx-linux/usb/src/common/log_util.cpp b/device/gxx-linux/usb/src/async_model/common/log_util.cpp similarity index 91% rename from device/gxx-linux/usb/src/common/log_util.cpp rename to device/gxx-linux/usb/src/async_model/common/log_util.cpp index 345df2f..e8036a5 100644 --- a/device/gxx-linux/usb/src/common/log_util.cpp +++ b/device/gxx-linux/usb/src/async_model/common/log_util.cpp @@ -160,6 +160,18 @@ int32_t log_cls::log_when_err(int32_t err, const char* oper_desc, log_level leve return err; } +void log_cls::log_memory_usage(const char* tag, bool print_screen, const char* prog_name) +{ + std::string memu("--Memory usage of "); + + memu += tag; + memu += ": " + sys_util::format_readable_bytes(sys_util::get_memory_usage(prog_name)) + "--"; + + if(print_screen) + printf("%s\n", memu.c_str()); + else if (log_cls::inst_) + log_cls::inst_->log(LOG_LEVEL_DEBUG, "%s\n", memu.c_str()); +} log_level log_cls::get_log_level(void) { if (log_cls::inst_) diff --git a/device/gxx-linux/usb/src/common/log_util.h b/device/gxx-linux/usb/src/async_model/common/log_util.h similarity index 90% rename from device/gxx-linux/usb/src/common/log_util.h rename to device/gxx-linux/usb/src/async_model/common/log_util.h index b298dc9..b8e5bd2 100644 --- a/device/gxx-linux/usb/src/common/log_util.h +++ b/device/gxx-linux/usb/src/async_model/common/log_util.h @@ -60,6 +60,7 @@ public: } } static int32_t log_when_err(int32_t err, const char* oper_desc, log_level level = LOG_LEVEL_WARNING); // log as: oper_desc = strerror(errno)\n. return real error number errno + static void log_memory_usage(const char* tag, bool print_screen = false/*call printf if this was true, or write down to file*/, const char* prog_name = "scan"); static log_level get_log_level(void); static std::string get_log_file(void); diff --git a/device/gxx-linux/usb/src/common/packet.h b/device/gxx-linux/usb/src/async_model/common/packet.h similarity index 93% rename from device/gxx-linux/usb/src/common/packet.h rename to device/gxx-linux/usb/src/async_model/common/packet.h index c30b7bd..00d1948 100644 --- a/device/gxx-linux/usb/src/common/packet.h +++ b/device/gxx-linux/usb/src/async_model/common/packet.h @@ -9,9 +9,13 @@ #endif #include +#define TEMPORARY_API + /////////////////////////////////////////////////////////////////////////////// // definitions ... #define CONFIG_NAME_MAX_LEN 32 // max bytes of configuration name +#define FLOAT_PRECISION .000001f +#define IS_FLOAT_EQUAL(x, y) (-FLOAT_PRECISION <= (x) - (y) && (x) - (y) <= FLOAT_PRECISION) #define MAKE_WORD(b0, b1) (((b0) & 0xff) | (((b1) << 8) & 0x0ff00)) #define ROGER(cmd) cmd##_ROGER #define PAIR_COMMAND(cmd) \ @@ -82,7 +86,7 @@ enum packet_cmd PACK_CMD_SCAN_BASE = 200, PAIR_COMMAND(PACK_CMD_SCAN_START), // start scanning, [in]: PACK_BASE, [out]: PACK_BASE PAIR_COMMAND(PACK_CMD_SCAN_IMG), // device -> host, PACK_BASE::payload - LPPACKIMAGE - PAIR_COMMAND(PACK_CMD_SCAN_PAPER), // device -> host, ONE paper has passed through the CIS. PACK_BASE::data - status of this paper + PAIR_COMMAND(PACK_CMD_SCAN_PAPER), // device -> host, ONE paper has passed through the CIS. PACK_BASE::data - index of this paper PACK_CMD_SCAN_FINISHED_ROGER, // device -> host, PACK_BASE::data is scanner_status PAIR_COMMAND(PACK_CMD_SCAN_STOP), // stop scanning, [in]: PACK_BASE, [out]: PACK_BASE //PAIR_COMMAND(PACK_CMD_SCAN_IMAGE_REQ), // get image request, [in]: PACK_BASE, [out] PACK_BASE on error, or PACK_BASE::payload - LPPACKIMAGE @@ -107,6 +111,13 @@ enum packet_cmd PACK_CMD_TOKEN_GET = 900, // Obtain the token of the required command, [in] PACK_BASE, [out] - PACK_BASE::payload - LPOPERTOKEN }; +enum img_cb_type +{ + IMG_CB_IMAGE = 0, + IMG_CB_STATUS, + IMG_CB_STOPPED, +}; + enum scanner_status { SCANNER_STATUS_READY = 0x10000, // status beginning, avoiding conficts with standards/system error code @@ -134,6 +145,15 @@ enum scanner_status SCANNER_STATUS_CFG_CHANGED, // PACK_BASE::payload - LPCFGVAL }; +// option affection if value changed, see SANE_INFO_xxx +enum opt_affect +{ + OPT_AFFECT_NONE = 0, + OPT_AFFECT_INEXACT = 1, + OPT_AFFECT_OTHERS = 2, + OPT_AFFECT_IMG_PARAM = 4, +}; + enum img_format { IMG_FMT_UNKNOWN = 0, // unknown format @@ -156,23 +176,25 @@ enum img_compression }; enum img_status { - IMG_STATUS_OK = 0, // normal - IMG_STATUS_DOUBLE, // double-feeded paper - IMG_STATUS_JAM, // jammed paper - IMG_STATUS_STAPLE, // staples on the paper - IMG_STATUS_SIZE_ERR, // size check failed - IMG_STATUS_DOGEAR, // paper has dogear - IMG_STATUS_BLANK, // blank image + IMG_STATUS_OK = 0, // normal + IMG_STATUS_DOUBLE = 1 << 0, // double-feeded paper + IMG_STATUS_JAM = 1 << 1, // jammed paper + IMG_STATUS_STAPLE = 1 << 2, // staples on the paper + IMG_STATUS_SIZE_ERR = 1 << 3, // size check failed + IMG_STATUS_DOGEAR = 1 << 4, // paper has dogear - common + IMG_STATUS_DOGEAR_PARTIAL = 1 << 5, // dogear - scanned partial + IMG_STATUS_BLANK = 1 << 6, // blank image }; enum data_type { DATA_TYPE_BOOL = 0, // (bool*) + DATA_TYPE_INT4, // (uint32_t*) + DATA_TYPE_FLOAT, // (double*) + DATA_TYPE_STRING, // (char*) with max_len space. befor and include me, keep same with SANE_TYPE_BOOL, SANE_TYPE_xxx ... + DATA_TYPE_INT1, // (uint8_t*) DATA_TYPE_INT2, // (uint16_t*) - DATA_TYPE_INT4, // (uint32_t*) DATA_TYPE_INT8, // (uint64_t*) - DATA_TYPE_FLOAT, // (double*) - DATA_TYPE_STRING, // (char*) with max_len space DATA_TYPE_CUSTOM, }; @@ -252,7 +274,7 @@ typedef struct _config_val uint8_t val_off; // option value offset in data uint8_t after_do; // see SANE_INFO_xxx in sane.h uint16_t val_size; // real size of value - uint16_t max_size; // max size of this option, this value has given in json::size + uint16_t max_size; // max size of this option, this value has given in gb_json::size char data[0]; // contains value and name. fetch them according name_off and val_off members. }CFGVAL, *LPCFGVAL; @@ -264,10 +286,10 @@ typedef struct _img_pos uint64_t paper_side : 3; // enum paper_side. front of paper(When scanning multiple sheets, the paper feeding side is the front side). (image-collector set) uint64_t back_rot : 2; // back rotation angle, enum rot_angle. (image-collector set) uint64_t channel_ind : 4; // index of color channel, enum clr_channel. (image-collector set) - uint64_t status : 4; // img_status. (image-collector set) + uint64_t status : 7; // img_status. (image-collector set) uint64_t split_ind : 7; // splitting order, from left to right and then top to bottom, based ZERO uint64_t multiout_ind : 4; // index of multi-out - uint64_t reserved : 6; // reserved + uint64_t reserved : 3; // reserved STRUCT_CONSTRUCTOR(_img_pos) }IMGPOS, * LPIMGPOS; diff --git a/device/gxx-linux/testusb/usb-rk3399/src/common/referer.cpp b/device/gxx-linux/usb/src/async_model/common/referer.cpp similarity index 100% rename from device/gxx-linux/testusb/usb-rk3399/src/common/referer.cpp rename to device/gxx-linux/usb/src/async_model/common/referer.cpp diff --git a/device/gxx-linux/usb/src/common/referer.h b/device/gxx-linux/usb/src/async_model/common/referer.h similarity index 98% rename from device/gxx-linux/usb/src/common/referer.h rename to device/gxx-linux/usb/src/async_model/common/referer.h index 47cb161..20218b7 100644 --- a/device/gxx-linux/usb/src/common/referer.h +++ b/device/gxx-linux/usb/src/async_model/common/referer.h @@ -186,6 +186,10 @@ public: } } } + size_t count(void) + { + return threads_.size(); + } }; diff --git a/device/gxx-linux/usb/src/async_model/common/sane_cfg.cpp b/device/gxx-linux/usb/src/async_model/common/sane_cfg.cpp new file mode 100644 index 0000000..67e4fb2 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/common/sane_cfg.cpp @@ -0,0 +1,911 @@ +#include "sane_cfg.h" + +#include "json/gb_json.h" +#include "log_util.h" + + + + + + + + + + + + + + + + + + + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// sane_cfg_provider: +sane_cfg_provider::sane_cfg_provider() +{} +sane_cfg_provider::~sane_cfg_provider() +{} + + std::string sane_cfg_provider::to_readable_string(void* data, data_type type) + { + if(type == DATA_TYPE_BOOL) + return *(bool*)data ? "true" : "false"; + else if(type == DATA_TYPE_INT4) + return std::to_string(*(int*)data); + else if(type == DATA_TYPE_FLOAT) + return std::to_string(*(double*)data); + else + return (char*)data; + } +std::string sane_cfg_provider::sane_option_value_get(gb_json* jsn, const char* key, std::string* strval) +{ + std::string type(""), ret(""); + bool got = false; + + if (jsn->get_value("type", type)) + { + if (type == "bool") + { + bool v = false; + if ((got = jsn->get_value(key, v))) + ret = std::string((char*)&v, sizeof(v)); + if(strval) + *strval = v ? "true" : "false"; + } + else if (type == "int") + { + int v = 0; + if ((got = jsn->get_value(key, v))) + ret = std::string((char*)&v, sizeof(v)); + if(strval) + *strval = std::to_string(v); + } + else if (type == "float") + { + double v = false; + if ((got = jsn->get_value(key, v))) + ret = std::string((char*)&v, sizeof(v)); + if(strval) + { + char buf[80] = {0}; + sprintf(buf, "%f", v); + *strval = buf; + } + } + else + { + got = jsn->get_value(key, ret); + if(strval) + *strval = ret; + } + if(!got) + { + printf("Failed to get '%s' value in JSON %s\n", key, jsn->to_string().c_str()); + } + } + else + { + printf("Lost 'type' field of json: %s\n", jsn->to_string().c_str()); + } + + return std::move(ret); +} +bool sane_cfg_provider::sane_option_value_set(gb_json* jsn, void* data, const char* key) +{ + std::string type(""); + bool ret = jsn->get_value("type", type); + + if (ret) + { + if (type == "bool") + { + ret = jsn->set_value(key, *(bool*)data); + } + else if (type == "int") + { + ret = jsn->set_value(key, *(int*)data); + } + else if (type == "float") + { + ret = jsn->set_value(key, *(double*)data); + } + else + { + ret = jsn->set_value(key, (char*)data); + } + } + + return ret; +} +bool sane_cfg_provider::sane_refine_range(gb_json* jsn, void* data, size_t* len) +{ + gb_json* range = nullptr; + bool ok = true; + + if(jsn->get_value("range", range) && range) + { + std::string type(""); + + jsn->get_value("type", type); + if(type == "int") + { + int val = 0, step = 1; + + range->get_value("step", step); + if(range->get_value("min", val)) + { + int upper = 0; + range->get_value("max", upper); + if(*(int*)data < val) + { + *(int*)data = val; + *len = sizeof(val); + ok = false; + } + else if(*(int*)data > upper) + { + *(int*)data = upper; + *len = sizeof(val); + ok = false; + } + else if((*(int*)data - val) % step) + { + int u = upper; + upper = *(int*)data - val; + upper += step / 2; + upper /= step; + upper *= step; + upper += val; + if(upper > u) + upper = u; + *(int*)data = upper; + *len = sizeof(val); + ok = false; + } + } + else + { + gb_json* en = range->first_child(); + + ok = false; + while(en) + { + if(en->value(val) && val == *(int*)data) + { + ok = true; + en->release(); + break; + } + en->release(); + en = range->next_child(); + } + if(!ok) + { + jsn->get_value("cur", val); + *(int*)data = val; + *len = sizeof(val); + } + } + } + else if(type == "float") + { + double val = .0f, step = 1.0f; + range->get_value("step", step); + if(range->get_value("min", val)) + { + double upper = 0; + range->get_value("max", upper); + if(*(double*)data < val) + { + *(double*)data = val; + *len = sizeof(val); + ok = false; + } + else if(*(double*)data > upper) + { + *(double*)data = upper; + *len = sizeof(val); + ok = false; + } + else + { + double u = upper; + upper = *(double*)data - val; + upper /= step; + upper -= (int)upper; + if(upper > .05f) + { + upper = *(double*)data - val; + upper /= step; + upper += .5f; + upper = (int)upper; + upper *= step; + upper += val; + if(upper > u) + upper = u; + + *(double*)data = upper; + *len = sizeof(val); + ok = false; + } + } + } + else + { + gb_json* en = range->first_child(); + + ok = false; + while(en) + { + if(en->value(val) && IS_FLOAT_EQUAL(val, *(double*)data)) + { + ok = true; + en->release(); + break; + } + en->release(); + en = range->next_child(); + } + if(!ok) + { + jsn->get_value("cur", val); + *(double*)data = val; + *len = sizeof(val); + } + } + } + else if(type == "string") + { + gb_json* en = range->first_child(); + + ok = false; + while(en) + { + if(en->value(type) && type == (char*)data) + { + ok = true; + en->release(); + break; + } + + en->release(); + en = range->next_child(); + } + if(!ok) + { + jsn->get_value("cur", type); + memcpy(data, type.c_str(), type.length()); + *len = type.length(); + } + } + + range->release(); + } + + return ok; +} +void sane_cfg_provider::update_option_enable_status(gb_json* opt, std::function get_opt) +{ + gb_json* depends = nullptr, *item = nullptr; + bool able = true, oper_and = false; + int type = 0; + std::string name(""), val(""); + + if(opt->get_value("depend_and", depends) && depends) + { + oper_and = true; + } + else if(opt->get_value("depend_or", depends) && depends) + { + oper_and = false; + } + + if(depends) + { + item = depends->first_child(); + while(item) + { + std::string exp(""); + if(item->value(exp)) + { + able = sane_cfg_provider::is_depends_item_ok(exp, &name, &type, &val, get_opt); + } + item->release(); + // if((!able && oper_and) || (able && !oper_and)) + if(able ^ oper_and) + break; + item = depends->next_child(); + } + depends->release(); + opt->set_value("enabled", able); + } +} +data_type sane_cfg_provider::type_from_string(const char* type_desc) +{ + if(strcmp(type_desc, "bool") == 0) + return DATA_TYPE_BOOL; + if(strcmp(type_desc, "int") == 0) + return DATA_TYPE_INT4; + if(strcmp(type_desc, "float") == 0) + return DATA_TYPE_FLOAT; + if(strcmp(type_desc, "string") == 0) + return DATA_TYPE_STRING; + + return DATA_TYPE_CUSTOM; +} + bool sane_cfg_provider::raw_value_in_json(gb_json* root, const char* key, std::string& val) + { + bool ret = true, bv = false; + int nv = 0; + double fv = .0f; + + if(root->get_value(key, bv)) + { + val = std::string((char*)&bv, sizeof(bv)); + } + else if(root->get_value(key, nv)) + { + val = std::string((char*)&nv, sizeof(nv)); + } + else if(root->get_value(key, fv)) + { + val = std::string((char*)&fv, sizeof(fv)); + } + else + { + ret = root->get_value(key, val); + } + + return ret; + } + +bool sane_cfg_provider::try_equal(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt, bool* result) +{ + bool oper_not = false, calc = true, handled = false; + size_t pos = exp.find("=="); + + if(pos == std::string::npos) + { + pos = exp.find("!="); + if(pos != std::string::npos) + { + oper_not = true; + } + } + if(pos != std::string::npos) + { + handled = true; + if(pos) + { + std::string types(""); + char buf[40] = {0}, *mem = nullptr; + size_t l = sizeof(buf) - 1; + + *name = exp.substr(0, pos); + get_opt(name->c_str(), buf, &l, "type"); + *type = sane_cfg_provider::type_from_string(buf); + l = 0; + get_opt(name->c_str(), mem, &l, "cur"); + mem = new char[l + 4]; + l += 4; + get_opt(name->c_str(), mem, &l, "cur"); + *val = std::string(mem, l); + delete[] mem; + } + exp.erase(0, pos + 2); + + if(*type == DATA_TYPE_BOOL) + { + calc = (*(bool*)val->c_str()) == (exp == "true"); + } + else if(*type == DATA_TYPE_INT4) + { + // in range ? + if(exp[0] == '[') + { + int lower = atoi(exp.c_str() + 1), + upper = 0; + pos = exp.find(","); + if(pos++ != std::string::npos) + upper = atoi(exp.c_str() + pos); + calc = lower <= *(int*)val->c_str() && *(int*)val->c_str() <= upper; + } + else + { + calc == *(int*)val->c_str() == atoi(exp.c_str()); + } + } + else if(*type == DATA_TYPE_FLOAT) + { + // in range ? + if(exp[0] == '[') + { + double lower = atof(exp.c_str() + 1), + upper = 0; + pos = exp.find(","); + if(pos++ != std::string::npos) + upper = atof(exp.c_str() + pos); + calc = lower <= *(double*)val->c_str() && *(double*)val->c_str() <= upper; + } + else + { + calc = IS_FLOAT_EQUAL(*(double*)val->c_str(), atof(exp.c_str())); + } + } + else if(*type == DATA_TYPE_STRING) + { + calc = *val == exp; + } + else + { + log_cls::log(LOG_LEVEL_FATAL, "Logic-operation error: un-supported type(%d) in '%s%s'\n", *type, oper_not ? "!=" : "==", exp.c_str()); + } + + *result = oper_not ^ calc; + } + + return handled; +} +bool sane_cfg_provider::try_great(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt, bool* result) +{ + bool oper_not = false, calc = true, handled = false; + size_t pos = exp.find(">"); + + if(pos == std::string::npos) + { + pos = exp.find("<="); + if(pos != std::string::npos) + { + oper_not = true; + } + } + if(pos != std::string::npos) + { + handled = true; + if(pos) + { + std::string types(""); + char buf[40] = {0}, *mem = nullptr; + size_t l = sizeof(buf) - 1; + + *name = exp.substr(0, pos); + get_opt(name->c_str(), buf, &l, "type"); + *type = sane_cfg_provider::type_from_string(buf); + l = 0; + get_opt(name->c_str(), mem, &l, "cur"); + mem = new char[l + 4]; + l += 4; + get_opt(name->c_str(), mem, &l, "cur"); + *val = std::string(mem, l); + delete[] mem; + } + exp.erase(0, pos + 1 + oper_not); + + if(*type == DATA_TYPE_INT4) + { + calc == *(int*)val->c_str() > atoi(exp.c_str()); + } + else if(*type == DATA_TYPE_FLOAT) + { + calc = *(double*)val->c_str() > atof(exp.c_str()); + } + else + { + log_cls::log(LOG_LEVEL_FATAL, "Logic-operation error: un-supported type(%d) in '%s%s'\n", *type, oper_not ? "<=" : ">", exp.c_str()); + } + + *result = oper_not ^ calc; + } + + return handled; +} +bool sane_cfg_provider::try_less(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt, bool* result) +{ + bool oper_not = false, calc = true, handled = false; + size_t pos = exp.find("<"); + + if(pos == std::string::npos) + { + pos = exp.find(">="); + if(pos != std::string::npos) + { + oper_not = true; + } + } + if(pos != std::string::npos) + { + handled = true; + if(pos) + { + std::string types(""); + char buf[40] = {0}, *mem = nullptr; + size_t l = sizeof(buf) - 1; + + *name = exp.substr(0, pos); + get_opt(name->c_str(), buf, &l, "type"); + *type = sane_cfg_provider::type_from_string(buf); + l = 0; + get_opt(name->c_str(), mem, &l, "cur"); + mem = new char[l + 4]; + l += 4; + get_opt(name->c_str(), mem, &l, "cur"); + *val = std::string(mem, l); + delete[] mem; + } + exp.erase(0, pos + 1 + oper_not); + + if(*type == DATA_TYPE_INT4) + { + calc == *(int*)val->c_str() < atoi(exp.c_str()); + } + else if(*type == DATA_TYPE_FLOAT) + { + calc = *(double*)val->c_str() < atof(exp.c_str()); + } + else + { + log_cls::log(LOG_LEVEL_FATAL, "Logic-operation error: un-supported type(%d) in '%s%s'\n", *type, oper_not ? ">=" : "<", exp.c_str()); + } + + *result = oper_not ^ calc; + } + + return handled; +} +bool sane_cfg_provider::is_depends_item_ok(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt) +{ + // ==, >, < + // !=, <=, >= + bool ok = true; + + if(!sane_cfg_provider::try_equal(exp, name, type, val, get_opt, &ok)) + { + if(!sane_cfg_provider::try_great(exp, name, type, val, get_opt, &ok)) + { + sane_cfg_provider::try_less(exp, name, type, val, get_opt, &ok); + } + } + + + return ok; +} + +int32_t sane_cfg_provider::inner_get_config(gb_json* root, void* buf, size_t* len, const char* cfg_name, std::string* strval) +{ + int ret = 0; + std::string val(""); + + if (!len) + return EINVAL; + + if (cfg_name) + { + gb_json* child = nullptr; + if (root->get_value(cfg_name, child) && child) + { + val = sane_cfg_provider::sane_option_value_get(child, "cur", strval); + child->release(); + } + else + { + ret = ENOENT; + } + } + else + { + val = root->to_string(); + } + + if (ret == 0) + { + if (*len < val.length()) + { + *len = val.length() + 4; + ret = ENOMEM; + } + else + { + memcpy(buf, val.c_str(), val.length()); + *len = val.length(); + } + } + + return ret; +} + + + + + + + + + + + + + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// : + +sane_cfg_mgr::sane_cfg_mgr() +{} +sane_cfg_mgr::~sane_cfg_mgr() +{ + cfg_api_.clear(); + for (auto& v : sane_waiters_) + v->release(); + sane_waiters_.clear(); +} + +gb_json* sane_cfg_mgr::load_all_configs(sane_cfg_provider* prvd) +{ + char * buf = nullptr; + size_t len = 0; + int32_t err = prvd->get_config(buf, &len); + gb_json * jsn = nullptr; + + if (err == ENOMEM) + { + len = ALIGN_INT(len, 8); + buf = (char*)malloc(len); + if (buf) + { + err = prvd->get_config(buf, &len); + if (err == 0) + { + jsn = new gb_json(); + if(!jsn->attach_text(buf)) + { + jsn->release(); + jsn = nullptr; + } + } + free(buf); + } + } + + return jsn; +} + +void sane_cfg_mgr::add_sane_api(const char* name, int ver, sane_cfg_provider* prvd) +{ + if (cfg_api_.count(name) && cfg_api_[name].ver >= ver) + return; + + cfg_api_[name].prvd = prvd; + if(std::find(cfg_sn_.begin(), cfg_sn_.end(), name) == cfg_sn_.end()) + cfg_sn_.push_back(name); +} +void sane_cfg_mgr::refresh_api(sane_cfg_provider* prvd, std::vector* given) +{ + char * buf = nullptr; + size_t len = 0; + gb_json *jsn = sane_cfg_mgr::load_all_configs(prvd), *child = nullptr; + + if (!jsn) + return; + + if (given) + { + for (auto& v : *given) + { + if (jsn->get_value(v.c_str(), child) && child) + { + int ver = 0; + if (child->get_value("ver", ver)) + add_sane_api(v.c_str(), ver, prvd); + child->release(); + } + } + } + else + { + child = jsn->first_child(); + while (child) + { + int ver = 0; + if (child->get_value("ver", ver)) + add_sane_api(child->key().c_str(), ver, prvd); + child->release(); + child = jsn->next_child(); + } + } + jsn->release(); +} +void sane_cfg_mgr::on_sane_provider_changed(sane_cfg_provider* prvd, bool add) +{ + if (add) + { + refresh_api(prvd); + } + else + { + std::vector lost; + for (auto& v : cfg_api_) + { + if (v.second.prvd == prvd) + lost.push_back(v.first); + } + for (auto& v : lost) + { + cfg_api_.erase(v); + + std::vector::iterator it = std::find(cfg_sn_.begin(), cfg_sn_.end(), v); + if(it != cfg_sn_.end()) + cfg_sn_.erase(it); + } + + char *buf = nullptr; + size_t size = 0, len = 0; + int32_t err = 0; + + for (auto& v : sane_waiters_) + { + refresh_api(v, &lost); + } + } + update_enable_status(); +} +std::string sane_cfg_mgr::get_all_configurations(void) +{ + std::map jsns; + gb_json* all = new gb_json(), * child = nullptr; + std::string text(""); + + for (auto& v : sane_waiters_) + { + gb_json* jsn = sane_cfg_mgr::load_all_configs(v); + if (jsn) + { + jsns[v] = jsn; + } + } + + for (auto& v : cfg_sn_) + { + if (cfg_api_.count(v) && jsns.count(cfg_api_[v].prvd)) + { + if (jsns[cfg_api_[v].prvd]->get_value(v.c_str(), child) && child) + { + all->set_value(v.c_str(), child); + child->release(); + } + } + } + text = all->to_string(); + all->release(); + + for (auto& v : jsns) + v.second->release(); + jsns.clear(); + + return std::move(text); +} +void sane_cfg_mgr::update_enable_status(void) +{ + auto get_opt = [&](const char* cfg_name, void* buf, size_t* len, const char* key) -> int32_t + { + std::string val(""); + int32_t ret = 0; + + for(auto& v: sane_waiters_) + { + ret = v->get_value(cfg_name, key, val); + if(ret != ENOENT) + break; + } + + if(ret == 0) + { + if(*len < val.length()) + { + *len = val.length(); + ret = ENOMEM; + } + else + { + memcpy(buf, val.c_str(), val.length()); + *len = val.length(); + } + } + + return ret; + }; + + for(auto& v: sane_waiters_) + { + v->update_enabled(get_opt); + } +} + +int sane_cfg_mgr::reg_sane_provider(sane_cfg_provider* prvd) +{ + LOCKER lock(locker_); + if (std::find(sane_waiters_.begin(), sane_waiters_.end(), prvd) == sane_waiters_.end()) + { + sane_waiters_.push_back(prvd); + prvd->add_ref(); + on_sane_provider_changed(prvd, true); + + return 0; + } + + return EEXIST; +} +int sane_cfg_mgr::unreg_sane_provider(sane_cfg_provider* prvd) +{ + LOCKER lock(locker_); + std::vector::iterator it = std::find(sane_waiters_.begin(), sane_waiters_.end(), prvd); + + if (it == sane_waiters_.end()) + return ENOENT; + + sane_waiters_.erase(it); + on_sane_provider_changed(prvd, false); + prvd->release(); + + return 0; +} + +// following APIs' parameters are same as sane_cfg_provider ... +int32_t sane_cfg_mgr::get_config(std::string& text, const char* cfg_name, std::string* str) +{ + if (cfg_name) + { + if (*cfg_name && cfg_api_.count(cfg_name)) + { + size_t len = 0; + int32_t err = cfg_api_[cfg_name].prvd->get_config(nullptr, &len, cfg_name, str); + + if (err == ENOMEM) + { + text.resize(len + 1); + err = cfg_api_[cfg_name].prvd->get_config(&text[0], &len, cfg_name, str); + text.resize(len); + } + + return err; + } + else + return ENOENT; + } + else + { + // get all ... + text = std::move(get_all_configurations()); + + return 0; + } +} +int32_t sane_cfg_mgr::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +{ + if (cfg_name) + { + if (cfg_api_.count(cfg_name)) + { + uint32_t affect = 0; + int32_t ret = cfg_api_[cfg_name].prvd->set_config(cfg_name, data, len, &affect); + + if(affect & OPT_AFFECT_OTHERS) + { + update_enable_status(); + } + + if(afterdo) + *afterdo = affect; + return ret; + } + else + return ENOENT; + } + else + return EINVAL; +} + diff --git a/device/gxx-linux/usb/src/common/sane_cfg.h b/device/gxx-linux/usb/src/async_model/common/sane_cfg.h similarity index 52% rename from device/gxx-linux/usb/src/common/sane_cfg.h rename to device/gxx-linux/usb/src/async_model/common/sane_cfg.h index 5ba98fc..25d571e 100644 --- a/device/gxx-linux/usb/src/common/sane_cfg.h +++ b/device/gxx-linux/usb/src/async_model/common/sane_cfg.h @@ -5,11 +5,13 @@ // created on 2023-04-04 -#include "referer.h" -#include "data.h" +#include "common/referer.h" +#include "common/packet.h" + #include #include #include +#include //{ @@ -32,10 +34,21 @@ // "range": ["A3", "8开", "A4", "A4横向", "16开", "16开横向", "A5", "A5横向", "A6", "A6横向", "B4", "B5", "B5横向", "B6", "B6横向", "Letter", "Letter横向", "Double Letter", "LEGAL", "匹配原始尺寸", "最大扫描尺寸自动裁切", "最大扫描尺寸", "三联试卷"] // }, //} +enum sane_after_do +{ + SANE_AFTER_DO_NOTHING = 0, + SANE_AFTER_DO_RELOAD_PARAM, + SANE_AFTER_DO_RELOAD_OPTION, +}; -class json; +class gb_json; class sane_cfg_provider : public refer { + static bool try_equal(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt, bool* result); + static bool try_great(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt, bool* result); + static bool try_less(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt, bool* result); + static bool is_depends_item_ok(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt); + public: sane_cfg_provider(); @@ -43,11 +56,16 @@ protected: virtual ~sane_cfg_provider(); public: - static std::string sane_option_value_get(json* jsn, const char* key = "cur"/*cur, default*/, std::string* strval = nullptr/*convert value into string*/); - static bool sane_option_value_set(json* jsn, void* data, const char* key = "cur"/*cur, default*/); + static std::string to_readable_string(void* data, data_type type); + static std::string sane_option_value_get(gb_json* jsn, const char* key = "cur"/*cur, default*/, std::string* strval = nullptr/*convert value into string*/); + static bool sane_option_value_set(gb_json* jsn, void* data, const char* key = "cur"/*cur, default*/); + static bool sane_refine_range(gb_json* jsn, void* data, size_t* len); // if 'data' is accept then return true, or else return false and new data set in 'data' and 'len' + static void update_option_enable_status(gb_json* opt, std::function get_opt); + static data_type type_from_string(const char* type_desc); + static bool raw_value_in_json(gb_json* root, const char* key, std::string& val); protected: - int32_t inner_get_config(json* root, void* buf, size_t* len, const char* cfg_name, std::string* strval); + int32_t inner_get_config(gb_json* root, void* buf, size_t* len, const char* cfg_name, std::string* strval); public: // Function: get all or given name configuration value @@ -83,9 +101,35 @@ public: // ENOENT - configuration 'cfg_name' was not found // EUCLEAN - content in 'data' was not exact, the exact value is stored in 'data', and bytes in 'len' virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) = 0; + + // Function: update field 'enabled' if a option changed and affect other options ... + // + // Parameters: get_opt - function to get option value, return value is the same as get_config + // + // cfg_name - option name + // + // buf - buffer to receive the option value + // + // len - [in]: length of 'buf'; [out]: real size of value + // + // key - the value key in JSON, e.g.: current value key is "cur" + // + // Return: none + virtual void update_enabled(std::function get_opt) = 0; + + // Function: get value of given key + // + // Parameters: name - option name + // + // key - key of the value in gb_json + // + // val = to receive the raw value. e.g. std::string(&bool, sizeof(bool)) + // + // Return: 0 - success, + // ENOENT - not found + virtual int32_t get_value(const char* name, const char* key, std::string& val) = 0; }; -class json; class sane_cfg_mgr : public refer { MUTEX locker_; @@ -96,16 +140,18 @@ class sane_cfg_mgr : public refer }SANEPROVIDER; std::vector sane_waiters_; std::map cfg_api_; + std::vector cfg_sn_; // record the origin sequence of configuration for cfg_api_ will sort void add_sane_api(const char* name, int ver, sane_cfg_provider* prvd); void refresh_api(sane_cfg_provider* prvd, std::vector* given = nullptr); void on_sane_provider_changed(sane_cfg_provider* prvd, bool add); std::string get_all_configurations(void); + void update_enable_status(void); public: sane_cfg_mgr(); - static json* load_all_configs(sane_cfg_provider* prvd); + static gb_json* load_all_configs(sane_cfg_provider* prvd); protected: ~sane_cfg_mgr(); @@ -115,22 +161,8 @@ public: int unreg_sane_provider(sane_cfg_provider* prvd); // return 0, ENOENT // following APIs' parameters are same as sane_cfg_provider ... - int32_t get_config(std::string& text, const char* cfg_name = nullptr, std::string* str = nullptr); + int32_t get_config(std::string& text, const char* cfg_name = nullptr, std::string* strval = nullptr); int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo); }; - -class img_processor : public sane_cfg_provider -{ -public: - img_processor(); - -protected: - ~img_processor(); - -public: - virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* str = nullptr) override; - virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; -}; - diff --git a/device/gxx-linux/usb/src/common/sys_util.cpp b/device/gxx-linux/usb/src/async_model/common/sys_util.cpp similarity index 96% rename from device/gxx-linux/usb/src/common/sys_util.cpp rename to device/gxx-linux/usb/src/async_model/common/sys_util.cpp index d322ea4..94afd43 100644 --- a/device/gxx-linux/usb/src/common/sys_util.cpp +++ b/device/gxx-linux/usb/src/async_model/common/sys_util.cpp @@ -547,6 +547,46 @@ namespace sys_util return val; } + std::string get_ip(void) + { + std::string val(sys_util::get_command_output("ifconfig | grep broadcast")); + char buf[40] = { 0 }; + + if (sscanf(val.c_str(), " inet %s", buf)) + val = buf; + + return std::move(val); + } + std::string get_mac(void) + { + std::string val(sys_util::get_command_output("ifconfig | grep ether")); + char buf[40] = { 0 }; + + if (sscanf(val.c_str(), " ether %s", buf)) + val = buf; + + return std::move(val); + } + std::string load_mini_file(const char* path) + { + FILE* src = fopen(path, "rb"); + std::string cont(""); + + if(src) + { + int len = 0; + + fseek(src, 0, SEEK_END); + len = ftell(src); + cont.resize(len); + fseek(src, 0, SEEK_SET); + fread(&cont[0], 1, len, src); + fclose(src); + } + + return cont; + } + static uint64_t from_dec_str(const char* str, const char** end) { uint64_t val = 0; diff --git a/device/gxx-linux/usb/src/common/sys_util.h b/device/gxx-linux/usb/src/async_model/common/sys_util.h similarity index 97% rename from device/gxx-linux/usb/src/common/sys_util.h rename to device/gxx-linux/usb/src/async_model/common/sys_util.h index 34fe405..ab78c50 100644 --- a/device/gxx-linux/usb/src/common/sys_util.h +++ b/device/gxx-linux/usb/src/async_model/common/sys_util.h @@ -75,6 +75,10 @@ namespace sys_util bool trim_right(std::string& str, const char* space = " \t"); uint64_t from_hex_str(const char* hex, const char** end = nullptr); // convert 0x100 to 256. parameter 'end' to receive the stopped position + std::string get_ip(void); + std::string get_mac(void); + std::string load_mini_file(const char* path); + // Function: convert number string to integer, support hex, dec, oct and bin // // Parameter: str - number string. diff --git a/device/gxx-linux/usb/src/async_model/hardware/hardware.cpp b/device/gxx-linux/usb/src/async_model/hardware/hardware.cpp new file mode 100644 index 0000000..8df685f --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/hardware/hardware.cpp @@ -0,0 +1,485 @@ +#include "hardware.h" + +#include "common/json/gb_json.h" +//{ +// "cis-mode": { +// "category": "base", +// "readonly" : false, +// "affect" : 2, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "CIS����ģʽ", +// "desc" : "����CIS��ɫ���߻ҶȵĹ���ģʽ", +// "type" : "string", +// "cur" : "��ɫ", +// "default" : "��ɫ", +// "size" : 12, +// "range": ["��ɫ", "�Ҷ�"] +// }, +// "cis-dpi": { +// "category": "base", +// "readonly" : false, +// "affect" : 2, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "CIS�ֱ���", +// "desc" : "����CIS�ɼ��ķֱ���", +// "type" : "int", +// "cur" : 200, +// "default" : 200, +// "size" : 4, +// "range": [200, 300] +// }, +// "cis-sample": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "CIS����Ƶ��", +// "desc" : "����CIS��ͷ�����Ĺ���Ƶ��", +// "type" : "int", +// "cur" : 256, +// "default" : 256, +// "size" : 4, +// "range": [128, 256, 512] +// }, +// "frame-h": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "CIS֡�߶�", +// "desc" : "����CISÿһ֡�ĸ߶�", +// "type" : "int", +// "cur" : 12, +// "default" : 12, +// "size" : 4, +// "range": [4, 8, 12, 16] +// }, +// "gain-front": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "��������", +// "desc" : "����CIS���澵ͷ������", +// "type" : "int", +// "cur" : 256, +// "default" : 256, +// "size" : 4, +// "range": [100, 200, 300, 600] +// }, +// "gain-back": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "��������", +// "desc" : "����CIS���澵ͷ������", +// "type" : "int", +// "cur" : 256, +// "default" : 256, +// "size" : 4, +// "range": [100, 200, 300, 600] +// }, +// "offset-front": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "����ƫ��", +// "desc" : "����CIS�����ƫ�ƾ���", +// "type" : "int", +// "cur" : 150, +// "default" : 150, +// "size" : 4, +// "range": [0, 50, 100, 150, 200] +// }, +// "offset-back": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "����ƫ��", +// "desc" : "����CIS�����ƫ�ƾ���", +// "type" : "int", +// "cur" : 150, +// "default" : 150, +// "size" : 4, +// "range": [0, 50, 100, 150, 200] +// }, +// "exposure-f-r": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "�����ɫ�����ع��", +// "desc" : "���������ɫ�������ع�ǿ��", +// "type" : "int", +// "cur" : 0, +// "default" : 0, +// "size" : 4, +// "range": { +// "min": -1000, +// "max": 1000, +// "step": 200 +// } +// }, +// "exposure-f-g": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "������ɫ�����ع��", +// "desc" : "����������ɫ�������ع�ǿ��", +// "type" : "int", +// "cur" : 0, +// "default" : 0, +// "size" : 4, +// "range": { +// "min": -1000, +// "max": 1000, +// "step": 200 +// } +// }, +// "exposure-f-b": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "������ɫ�����ع��", +// "desc" : "����������ɫ�������ع�ǿ��", +// "type" : "int", +// "cur" : 0, +// "default" : 0, +// "size" : 4, +// "range": { +// "min": -1000, +// "max": 1000, +// "step": 200 +// } +// }, +// "exposure-b-r": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "�����ɫ�����ع��", +// "desc" : "�����������ɫ�������ع�ǿ��", +// "type" : "int", +// "cur" : 0, +// "default" : 0, +// "size" : 4, +// "range": { +// "min": -1000, +// "max": 1000, +// "step": 200 +// } +// }, +// "exposure-b-g": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "������ɫ�����ع��", +// "desc" : "���ñ�����ɫ�������ع�ǿ��", +// "type" : "int", +// "cur" : 0, +// "default" : 0, +// "size" : 4, +// "range": { +// "min": -1000, +// "max": 1000, +// "step": 200 +// } +// }, +// "exposure-b-b": { +// "category": "base", +// "readonly" : false, +// "affect" : 0, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "pos" : 0, +// "unit" : "None", +// "title" : "������ɫ�����ع��", +// "desc" : "���ñ�����ɫ�������ع�ǿ��", +// "type" : "int", +// "cur" : 0, +// "default" : 0, +// "size" : 4, +// "range": { +// "min": -1000, +// "max": 1000, +// "step": 200 +// } +// }, +//} +static std::string json_text = + "{\"cis-mode\":{\"category\":\"base\",\"readonly\":false,\"affect\":2,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"CIS\\u5de5\\u4f5c\\u6a21\\u5f0f\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u5f69\\u8272\\u6216\\u8005\\u7070\\u5ea6\\u7684\\u5de5\\u4f5c\\u6a21\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u5f69\\u8272\",\"default\":\"\\u5f69\\u8272\",\"size\":12,\"range\":[\"\\u5f69\\u8272\",\"\\u7070\\u5ea6\"]},\"cis-dpi\":{\"category\":\"base\",\"readonly\":false,\"affect\":2,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"CIS\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u91c7\\u96c6\\u7684\\u5206\\u8fa8\\u7387\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":[200,300]},\"cis-sample\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"CIS\\u91c7\\u6837\\u9891\\u7387\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u955c\\u5934\\u91c7\\u6837\\u7684\\u5de5\\u4f5c\\u9891\\u7387\",\"type\":\"int\",\"cur\":256,\"default\":256,\"size\":4,\"range\":[128,256,512]},\"frame-h\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"CIS\\u5e27\\u9ad8\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u6bcf\\u4e00\\u5e27\\u7684\\u9ad8\\u5ea6\",\"type\":\"int\",\"cur\":12,\"default\":12,\"size\":4,\"range\":[4,8,12,16]},\"gain-front\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u589e\\u76ca\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u6b63\\u9762\\u955c\\u5934\\u7684\\u589e\\u76ca\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":[100,200,300,600]},\"gain-back\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u589e\\u76ca\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u80cc\\u9762\\u955c\\u5934\\u7684\\u589e\\u76ca\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":[100,200,300,600]},\"offset-front\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u504f\\u79fb\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u6b63\\u9762\\u7684\\u504f\\u79fb\\u8ddd\\u79bb\",\"type\":\"int\",\"cur\":150,\"default\":150,\"size\":4,\"range\":[0,50,100,150,200]},\"offset-back\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u504f\\u79fb\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u80cc\\u9762\\u7684\\u504f\\u79fb\\u8ddd\\u79bb\",\"type\":\"int\",\"cur\":150,\"default\":150,\"size\":4,\"range\":[0,50,100,150,200]},\"exposure-f-r\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u7ea2\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u6b63\\u9762\\u7ea2\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-f-g\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u7eff\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u6b63\\u9762\\u7eff\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-f-b\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u84dd\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u6b63\\u9762\\u84dd\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-b-r\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u7ea2\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u6b63\\u80cc\\u9762\\u7ea2\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-b-g\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u7eff\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u80cc\\u9762\\u7eff\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-b-b\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u84dd\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u80cc\\u9762\\u84dd\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"scan-count\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":true,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u626b\\u63cf\\u5f20\\u6570\",\"desc\":\"\\u8bbe\\u7f6e\\u626b\\u63cf\\u7684\\u7eb8\\u5f20\\u6570\\u91cf\uFF0C\\u201C-1\\u201D\\u4e3a\\u8fde\\u7eed\\u626b\\u63cf\",\"type\":\"int\",\"cur\":-1,\"default\":-1,\"size\":4,\"range\":[-1,1,2,3,4,5,6,7,8,9,10]}}"; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class image_capture +#ifdef TEMPORARY_API +extern int32_t (*scan_start)(void); +extern int32_t (*scan_stop)(void); +extern int32_t (*set_dpi)(int*, int*); +extern int32_t (*set_scan_num)(int); +#endif + +image_capture::image_capture(std::function receiver) + : img_keeper_(receiver), cfg_(new gb_json()) +{ + cfg_->attach_text(&json_text[0]); + memset(&api_, 0, sizeof(api_)); +} +image_capture::~image_capture() +{ + cfg_->release(); +} + +int32_t image_capture::set(const char* name, void* data, size_t* len) +{ + int32_t ret = ENOENT; + int val = *(int*)data; + std::string n(name); + CIS_API api = CIS_API(); + gb_json *child = nullptr; + + if(cfg_->get_value(name, child) && child) + { + sane_cfg_provider::sane_refine_range(child, data, len); + + if (n == "cis-mode") + { + int clr = 1; + std::string gray("\xE7\x81\xB0\xE5\xBA\xA6"), + color("\xE5\xBD\xA9\xE8\x89\xB2"); + + n = std::string((char*)data); + if (n == gray) // �Ҷ� + { + clr = 0; + } + else + { + if (n != color) + { + ret = EUCLEAN; + strcpy((char*)data, color.c_str()); + *len = color.length(); + } + } + + val = clr; + if (api_.set_color_mode) + { + ret = 0; + api_.set_color_mode(&val); + if (val != clr) + { + if (val == 0) + { + strcpy((char*)data, gray.c_str()); + *len = gray.length(); + } + else + { + strcpy((char*)data, color.c_str()); + *len = color.length(); + } + ret = EUCLEAN; + } + } + } + else if (n == "cis-dpi") + { + api = api_.set_dpi; + } + else if (n == "cis-sample") + { + api = api_.set_sample; + } + else if (n == "frame-h") + { + api = api_.set_frame_height; + } + else if (n == "gain-front") + { + api = api_.set_gain_front; + } + else if (n == "gain-back") + { + api = api_.set_gain_back; + } + else if (n == "offset-front") + { + api = api_.set_offset_front; + } + else if (n == "offset-back") + { + api = api_.set_offset_back; + } + else if (n == "exposure-f-r") + { + api = api_.set_exposure_front_red; + } + else if (n == "exposure-f-g") + { + api = api_.set_exposure_front_green; + } + else if (n == "exposure-f-b") + { + api = api_.set_exposure_front_blue; + } + else if (n == "exposure-b-r") + { + api = api_.set_exposure_back_red; + } + else if (n == "exposure-b-g") + { + api = api_.set_exposure_back_green; + } + else if (n == "exposure-b-b") + { + api = api_.set_exposure_back_blue; + } + else if(n == "scan-count") + { + set_scan_num(*(int*)data); + child->set_value("cur", *(int*)data); + } + child->release(); + } + + if (api) + { + ret = 0; + api(&val); + if (val != *(int*)data) + { + *(int*)data = val; + ret = EUCLEAN; + } + } + + return ret; +} + +int32_t image_capture::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) +{ + return inner_get_config(cfg_, buf, len, cfg_name, strval); +} +int32_t image_capture::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +{ + int ret = ENOENT; + gb_json* child = nullptr; + + if (cfg_->get_value(cfg_name, child) && child) + { + bool exact = sane_cfg_provider::sane_refine_range(child, data, len); + ret = set(cfg_name, data, len); + if (ret == 0 || ret == EUCLEAN) + { + sane_option_value_set(child, data); + if (afterdo) + { + child->get_value("affect", ret); + *afterdo = ret; + } + if(!exact) + ret = EUCLEAN; + } + child->release(); + } + + return ret; +} +void image_capture::update_enabled(std::function get_opt) +{ + sane_cfg_provider::update_option_enable_status(cfg_, get_opt); +} +int32_t image_capture::get_value(const char* name, const char* key, std::string& val) +{ + gb_json* child = nullptr; + int32_t ret = ENOENT; + + if(cfg_->get_value(name, child) && child) + { + if(sane_cfg_provider::raw_value_in_json(child, key, val)) + ret = 0; + } + + return ret; +} + +int32_t image_capture::start(void) +{ +#ifdef TEMPORARY_API + return scan_start(); +#else + return EINVAL; +#endif +} +int32_t image_capture::stop(void) +{ +#ifdef TEMPORARY_API + return scan_stop(); +#else + return EINVAL; +#endif +} +int image_capture::set_dpi(int* dpi_x, int* dpi_y) +{ + return ::set_dpi(dpi_x, dpi_y); +} \ No newline at end of file diff --git a/device/gxx-linux/usb/src/async_model/hardware/hardware.h b/device/gxx-linux/usb/src/async_model/hardware/hardware.h new file mode 100644 index 0000000..4ee6361 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/hardware/hardware.h @@ -0,0 +1,73 @@ +#pragma once + +// image process interface classes +// +// created on 2023-04-19 +// + +#include "common/referer.h" +#include "common/packet.h" +#include "common/sane_cfg.h" +#include + +class gb_json; + +#define CIS_API std::function // return error code, set real value to parameter if in-value was not exact +#define CAPTURED_IMG_RECEIVER_PROTO void(int data_type/*img_cb_type*/, void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel clr, img_status, bool img_new, bool img_over) + +typedef struct _cis_api +{ + CIS_API set_color_mode; + CIS_API set_dpi; + CIS_API set_sample; + CIS_API set_frame_height; + CIS_API set_gain_front; + CIS_API set_gain_back; + CIS_API set_offset_front; + CIS_API set_offset_back; + CIS_API set_exposure_front_red; + CIS_API set_exposure_front_green; + CIS_API set_exposure_front_blue; + CIS_API set_exposure_back_red; + CIS_API set_exposure_back_green; + CIS_API set_exposure_back_blue; +}CISAPI, *LPCISAPI; + +class image_capture : public sane_cfg_provider +{ + gb_json* cfg_; + CISAPI api_; + std::function img_keeper_; + + int32_t set(const char* name, void* data, size_t* len); + +public: + image_capture(std::function receiver); + +protected: + ~image_capture(); + + // sane_cfg_provider +public: + virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; + virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + virtual void update_enabled(std::function get_opt) override; + virtual int32_t get_value(const char* name, const char* key, std::string& val) override; + +public: + void set_api(LPCISAPI api); + +public: + int32_t start(void); + int32_t stop(void); + + // Function: set resolution of hardware/CIS + // + // Parameters: dpi_x - [in]resolution of x axis to be set; [out]applied value, not set if it was nullptr + // + // dpi_y - [in]resolution of y axis to be set; [out]applied value, not set if it was nullptr + // + // Return: always 0. if input value is not accessible, the exact value is stored into the var + int set_dpi(int* dpi_x, int* dpi_y); +}; + diff --git a/device/gxx-linux/usb/src/async_model/img_process/algs/dogear.cpp b/device/gxx-linux/usb/src/async_model/img_process/algs/dogear.cpp new file mode 100644 index 0000000..3ce2341 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/img_process/algs/dogear.cpp @@ -0,0 +1,193 @@ +#include "dogear.h" + + +#include "common/json/gb_json.h" +#include "imageprocess/ImageApplyDogEarDetection.h" + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// + + + +static std::string dogear_jsn("{\"is-check-dog-ear\":{\"category\":\"base\",\"readonly\":false,\"affect\":2,\"group\":\"feeder\",\"visible\":true,\"field\":\"imgproc\",\"pos\":10,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6298\\u89d2\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u6587\\u7a3f\\u662f\\u5426\\u5b58\\u5728\\u6298\\u89d2\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"dog-ear-size\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"imgproc\",\"pos\":11,\"ver\":1,\"unit\":\"None\",\"title\":\" \\u6298\\u89d2\\u5927\\u5c0f\",\"desc\":\"\\u503c\\u8d8a\\u5c0f\\u80fd\\u68c0\\u6d4b\\u5230\\u7684\\u6298\\u89d2\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":70,\"default\":70,\"size\":4,\"range\":{\"min\":0,\"max\":100,\"step\":1},\"depend_or\":[\"is-check-dog-ear==true\"]},\"dog-ear-size-outer\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":false,\"field\":\"imgproc\",\"pos\":12,\"ver\":1,\"unit\":\"None\",\"title\":\" \\u6298\\u89d2\\u5927\\u5c0f(\\u5728\\u56fe\\u7247\\u5916)\",\"desc\":\"\\u503c\\u8d8a\\u5c0f\\u80fd\\u68c0\\u6d4b\\u5230\\u7684\\u6298\\u89d2\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":70,\"default\":70,\"size\":4,\"range\":{\"min\":0,\"max\":100,\"step\":1},\"depend_or\":[\"is-check-dog-ear==true\"]},\"dog-ear-zoom-x\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":false,\"field\":\"imgproc\",\"pos\":13,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u539f\\u56feX\\u8f74\\u7f29\\u653e\\u6bd4\\u4f8b\",\"desc\":\"\\u5BF9\\u4E8E\\u5927\\u5C3A\\u5BF8\\u56FE\\u50CF\\u800C\\u8A00\\u901A\\u8FC7zoom\\u7F29\\u5C0F\\u56FE\\u50CF\\u53EF\\u51CF\\u5C11\\u8BA1\\u7B97\\u91CF\\u3002\\u9ED8\\u8BA4\\u503C1.0\",\"type\":\"float\",\"cur\":1.0,\"default\":1.0,\"size\":8,\"range\":{\"min\":0.1,\"max\":4.0,\"step\":0.5},\"depend_or\":[\"is-check-dog-ear==true\"]},\"dog-ear-zoom-y\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":false,\"field\":\"imgproc\",\"pos\":14,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u539f\\u56fey\\u8f74\\u7f29\\u653e\\u6bd4\\u4f8b\",\"desc\":\"\\u5BF9\\u4E8E\\u5927\\u5C3A\\u5BF8\\u56FE\\u50CF\\u800C\\u8A00\\u901A\\u8FC7zoom\\u7F29\\u5C0F\\u56FE\\u50CF\\u53EF\\u51CF\\u5C11\\u8BA1\\u7B97\\u91CF\\u3002\\u9ED8\\u8BA4\\u503C1.0\",\"type\":\"float\",\"cur\":1.0,\"default\":1.0,\"size\":8,\"range\":{\"min\":0.1,\"max\":4.0,\"step\":0.5},\"depend_or\":[\"is-check-dog-ear==true\"]},\"dog-ear-threashold\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":false,\"field\":\"imgproc\",\"pos\":15,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u4e8c\\u503c\\u5316\\u9608\\u503c\",\"desc\":\"\\u6298\\u89d2\\u68c0\\u6d4b\\u4e8c\\u503c\\u5316\\u53c2\\u6570\",\"type\":\"int\",\"cur\":40,\"default\":40,\"size\":4,\"range\":{\"min\":10,\"max\":100,\"step\":5},\"depend_or\":[\"is-check-dog-ear==true\"]}}"); + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class img_algs +dogear::dogear() : dog_(new CImageApplyDogEarDetection()), root_(new gb_json()) + , name_("is-check-dog-ear"), pos_(0), ver_(0), enable_(true) + , threshold_(40), zoom_x_(1.0f), zoom_y_(1.0f), size_inner_(50), size_outer_(50) +{ + root_->attach_text(&dogear_jsn[0]); + + gb_json* child = nullptr; + + root_->get_value(name_.c_str(), child); + if(child) + { + int n = 0; + child->get_value("cur", enable_); + child->get_value("pos", n); pos_ = n; + child->get_value("ver", n); ver_ = n; + child->release(); + } + + // int threshold_; // dog-ear-threashold + // double zoom_x_; // dog-ear-zoom-x + // double zoom_y_; // dog-ear-zoom-y + // int size_inner_; // dog-ear-size + // int size_outer_; // dog-ear-size-outer + size_t len = 0; + +#define GET_INNER_VAR(v, n) \ + len = sizeof(v); \ + get_config(&v, &len, #n); + + GET_INNER_VAR(threshold_, dog-ear-threashold); + GET_INNER_VAR(zoom_x_, dog-ear-zoom-x); + GET_INNER_VAR(zoom_y_, dog-ear-zoom-y); + GET_INNER_VAR(size_inner_, dog-ear-size); + GET_INNER_VAR(size_outer_, dog-ear-size-outer); +} +dogear::~dogear() +{ + root_->release(); + delete dog_; +} + + +int32_t dogear::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) +{ + if(cfg_name) + { + return inner_get_config(root_, buf, len, cfg_name, strval); + } + else + { + if(!len) + return EINVAL; + + std::string val(root_->to_string()); + + if(*len < val.length()) + { + *len = val.length() + 4; + + return ENOMEM; + } + + strcpy((char*)buf, val.c_str()); + *len = val.length(); + } + + return 0; +} +int32_t dogear::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +{ + gb_json* child = nullptr; + int32_t ret = ENOENT; + + if(root_->get_value(cfg_name, child) && child) + { + int val = 0; + + ret = 0; + if(strcmp(cfg_name, name_.c_str()) == 0) + { + enable_ = *(bool*)data; + child->set_value("cur", enable_); + } + else if(strcmp(cfg_name, "dog-ear-size") == 0) + { + ret = sane_cfg_provider::sane_refine_range(child, data, len) ? 0 : EUCLEAN; + sane_cfg_provider::sane_option_value_set(child, data); + size_inner_ = *(int*)data; + } + else if(strcmp(cfg_name, "dog-ear-size-outer") == 0) + { + ret = sane_cfg_provider::sane_refine_range(child, data, len) ? 0 : EUCLEAN; + sane_cfg_provider::sane_option_value_set(child, data); + size_outer_ = *(int*)data; + } + else if(strcmp(cfg_name, "dog-ear-threashold") == 0) + { + ret = sane_cfg_provider::sane_refine_range(child, data, len) ? 0 : EUCLEAN; + sane_cfg_provider::sane_option_value_set(child, data); + threshold_ = *(int*)data; + } + else if(strcmp(cfg_name, "dog-ear-zoom-x") == 0) + { + ret = sane_cfg_provider::sane_refine_range(child, data, len) ? 0 : EUCLEAN; + sane_cfg_provider::sane_option_value_set(child, data); + zoom_x_ = *(double*)data; + } + else if(strcmp(cfg_name, "dog-ear-zoom-y") == 0) + { + ret = sane_cfg_provider::sane_refine_range(child, data, len) ? 0 : EUCLEAN; + sane_cfg_provider::sane_option_value_set(child, data); + zoom_y_ = *(double*)data; + } + dog_->setDistance(size_inner_, size_outer_, threshold_, zoom_x_, zoom_y_); + + if(afterdo) + { + child->get_value("affect", val); + *afterdo = val; + } + + child->release(); + } + + return ret; +} +void dogear::update_enabled(std::function get_opt) +{ + gb_json* child = root_->first_child(); + while(child) + { + sane_cfg_provider::update_option_enable_status(child, get_opt); + child->release(); + child = root_->next_child(); + } +} +int32_t dogear::get_value(const char* name, const char* key, std::string& val) +{ + int32_t ret = ENOENT; + gb_json* child = nullptr; + + if(root_->get_value(name, child) && child) + { + ret = sane_cfg_provider::raw_value_in_json(child, key, val) ? 0 : ENOENT; + child->release(); + } + + return ret; +} + +img_one_paper* dogear::execute(img_one_paper* img) +{ + for(auto& v : img->images_queue()) + dog_->apply(v, 0); + img->add_ref(); + + return img; +} +bool dogear::is_enabled(std::function get_opt_value) +{ + return enable_; +} + +uint32_t dogear::position(void) +{ + return pos_; +} +uint32_t dogear::version(void) +{ + return ver_; +} +const char* dogear::option_name(void) +{ + return name_.c_str(); +} + + diff --git a/device/gxx-linux/usb/src/async_model/img_process/algs/dogear.h b/device/gxx-linux/usb/src/async_model/img_process/algs/dogear.h new file mode 100644 index 0000000..0d5692e --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/img_process/algs/dogear.h @@ -0,0 +1,189 @@ +#pragma once + +// dogear algorithm +// +// created on 2023-04-23 +// + +#include "img_algorithm.h" + + + +//{ +// "is-check-dog-ear": { +// "category": "base", +// "readonly": false, +// "affect": 0, +// "group": "feeder", +// "visible": true, +// "field": "imgproc", +// "pos": 10, +// "ver": 1, +// "unit": "None", +// "title": "折角检测", +// "desc": "检测文稿是否存在折角", +// "type": "bool", +// "cur": false, +// "default": false, +// "size": 4 +// }, +// "dog-ear-size": { +// "category": "base", +// "readonly": false, +// "affect": 0, +// "group": "feeder", +// "visible": true, +// "field": "imgproc", +// "pos": 11, +// "ver": 1, +// "unit": "None", +// "title": " 折角大小", +// "desc": "值越小,能检测到的折角越小", +// "type": "int", +// "cur": 70, +// "default": 70, +// "size": 4, +// "range": { +// "min": 0, +// "max": 100, +// "step": 1 +// }, +// "depend_or": ["is-check-dog-ear==true"] +// }, +// "dog-ear-size-outer": { +// "category": "base", +// "readonly": false, +// "affect": 0, +// "group": "feeder", +// "visible": false, +// "field": "imgproc", +// "pos": 12, +// "ver": 1, +// "unit": "None", +// "title": " 折角大小(超出图片)", +// "desc": "值越小,能检测到的折角越小", +// "type": "int", +// "cur": 70, +// "default": 70, +// "size": 4, +// "range": { +// "min": 0, +// "max": 100, +// "step": 1 +// }, +// "depend_or": ["is-check-dog-ear==true"] +// }, +// "dog-ear-zoom-x": { +// "category": "base", +// "readonly": false, +// "affect": 0, +// "group": "feeder", +// "visible": false, +// "field": "imgproc", +// "pos": 13, +// "ver": 1, +// "unit": "None", +// "title": "原图X轴缩放比例", +// "desc": "对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0", +// "type": "float", +// "cur": 1.0, +// "default": 1.0, +// "size": 4, +// "range": [ +// "min": 0.1, +// "max": 4.0, +// "step": 0.5 +// ], +// "depend_or": ["is-check-dog-ear==true"] +// }, +// "dog-ear-zoom-y": { +// "category": "base", +// "readonly": false, +// "affect": 0, +// "group": "feeder", +// "visible": false, +// "field": "imgproc", +// "pos": 14, +// "ver": 1, +// "unit": "None", +// "title": "原图y轴缩放比例", +// "desc": "对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0", +// "type": "float", +// "cur": 1.0, +// "default": 1.0, +// "size": 4, +// "range": [ +// "min": 0.1, +// "max": 4.0, +// "step": 0.5 +// ], +// "depend_or": ["is-check-dog-ear==true"] +// }, +// "dog-ear-threashold": { +// "category": "base", +// "readonly": false, +// "affect": 0, +// "group": "feeder", +// "visible": false, +// "field": "imgproc", +// "pos": 15, +// "ver": 1, +// "unit": "None", +// "title": "二值化阈值", +// "desc": "折角检测二值化参数", +// "type": "int", +// "cur": 40, +// "default": 40, +// "size": 4, +// "range": [ +// "min": 10, +// "max": 100, +// "step": 5 +// ], +// "depend_or": ["is-check-dog-ear==true"] +// }, +//} + +class CImageApplyDogEarDetection; +class gb_json; + +/// 二值化阈值 +/// 原图X轴缩放比例,对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0(不缩放) +/// 原图Y轴缩放比例,对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0(不缩放) +/// 理论顶点到实际轮廓最小距离的阈值(折角在图片内),大于该阈值则判定为折角,默认值50(像素) +/// 理论顶点到实际轮廓最小距离的阈值(折角超出图片),大于该阈值则判定为折角,默认值50(像素) +class dogear : public img_alg +{ + CImageApplyDogEarDetection* dog_; + gb_json* root_; + + std::string name_; + uint32_t pos_; + uint32_t ver_; + bool enable_; + + int threshold_; // dog-ear-threashold + double zoom_x_; // dog-ear-zoom-x + double zoom_y_; // dog-ear-zoom-y + int size_inner_; // dog-ear-size + int size_outer_; // dog-ear-size-outer + +public: + dogear(void); +protected: + ~dogear(); + +public: + virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; + virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + virtual void update_enabled(std::function get_opt) override; + virtual int32_t get_value(const char* name, const char* key, std::string& val) override; + +public: + img_one_paper* execute(img_one_paper* img) override; + bool is_enabled(std::function get_opt_value) override; + + uint32_t position(void) override; + uint32_t version(void) override; + const char* option_name(void) override; +}; diff --git a/device/gxx-linux/usb/src/async_model/img_process/algs/img_algorithm.cpp b/device/gxx-linux/usb/src/async_model/img_process/algs/img_algorithm.cpp new file mode 100644 index 0000000..df10937 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/img_process/algs/img_algorithm.cpp @@ -0,0 +1,511 @@ +#include "img_algorithm.h" + + +#include "dogear.h" +#include "common/json/gb_json.h" +#include "../capimage/hgutils.h" + +#ifdef TEMPORARY_API +extern int32_t (*set_dpi)(int*, int*); +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class img_one_paper +img_one_paper::img_one_paper() +{ +} +img_one_paper::~img_one_paper() +{ + clear(); +} + +void img_one_paper::clear(void) +{ + imgs_.clear(); +} + +int img_one_paper::init_from(void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel cc, img_status status, bool img_new, bool img_over) +{ + PACKIMAGE pk; + + memset(&pk, 0, sizeof(pk)); + pk.pos.new_img = img_new; + pk.pos.img_over = img_over; + pk.pos.paper_ind = paper_ind; + pk.pos.paper_side = side; + pk.pos.status = status; + pk.pos.channel_ind = cc; + pk.resolution_x = dpi_x; + pk.resolution_y = dpi_y; + if (cc == COLOR_CHANNEL_RGBA) + { + pk.width = w / 4; + pk.channels = 4; + } + else if (cc == COLOR_CHANNEL_RGB) + { + pk.width = w / 3; + pk.channels = 3; + } + else + { + pk.width = w; + pk.channels = 1; + } + pk.height = h; + + return init_from(data, w, h, &pk); +} +int img_one_paper::init_from(void* data, size_t w, size_t h, LPPACKIMAGE pimg) +{ + int ret = 0; + PROCIMG img; + + clear(); + memcpy(&img.head, pimg, sizeof(img.head)); + img.img = std::move(cv::Mat(h, w, CV_8UC1, data)); + imgs_.push_back(std::move(img)); + + return ret; +} +std::vector& img_one_paper::images_queue(void) +{ + return imgs_; +} + + + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class img_alg +img_alg::img_alg() : pos_(100), ver_(1), name_("") +{ +} +img_alg::~img_alg() +{ +} + +img_alg* img_alg::create_image_algorithm(img_alg_type type) +{ + if(type == IMG_ALG_DOGEAR) + return dynamic_cast(new dogear()); + if(type == IMG_ALG_ADJUST_DPI) + return dynamic_cast(new img_resizer()); + if(type == IMG_ALG_ADJUST_COLOR) + return dynamic_cast(new color_correct()); + + return nullptr; +} + +uint32_t img_alg::position(void) +{ + return pos_; +} +uint32_t img_alg::version(void) +{ + return ver_; +} +const char* img_alg::option_name(void) +{ + return name_.c_str(); +} + + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class img_resizer +// { +// "color-correct": { +// "category": "base", +// "readonly": false, +// "visible": true, +// "field": "imgproc", +// "group": "imgproc", +// "pos": 100, +// "unit": "none", +// "ver": 1, +// "title": "颜色校正", +// "desc": "校正由于硬件特性产生的色偏,使图片颜色更接近真实", +// "type": "string", +// "cur": "普通模式", +// "default": "普通模式", +// "size": 20, +// "range": ["不校正", "普通模式", "增强模式"] +// } +// } +static std::string color_correct_json = + "{\"color-correct\":{\"category\":\"base\",\"readonly\":false,\"visible\":true,\"field\":\"imgproc\",\"group\":\"imgproc\",\"pos\":100,\"unit\":\"none\",\"ver\":1,\"title\":\"\\u989c\\u8272\\u6821\\u6b63\",\"desc\":\"\\u6821\\u6b63\\u7531\\u4e8e\\u786c\\u4ef6\\u7279\\u6027\\u4ea7\\u751f\\u7684\\u8272\\u504f\\uFF0C\\u4f7f\\u56fe\\u7247\\u989c\\u8272\\u66f4\\u63a5\\u8fd1\\u771f\\u5b9e\",\"type\":\"string\",\"cur\":\"\\u666e\\u901a\\u6a21\\u5f0f\",\"default\":\"\\u666e\\u901a\\u6a21\\u5f0f\",\"size\":20,\"range\":[\"\\u4e0d\\u6821\\u6b63\",\"\\u666e\\u901a\\u6a21\\u5f0f\",\"\\u589e\\u5f3a\\u6a21\\u5f0f\"]}}"; + +color_correct::color_correct() : enable_(true), enhance_(false) +{ + name_ = "color-correct"; + cfg_ = new gb_json(); + cfg_->attach_text(&color_correct_json[0]); + + gb_json* child = nullptr; + + if(cfg_->get_value(name_.c_str(), child) && child) + { + std::string val(""); + + child->get_value("cur", val); + on_cur_val_changed(val); + child->get_value("ver", ver_); + child->get_value("pos", pos_); + child->release(); + } +} +color_correct::~color_correct() +{ + cfg_->release(); +} + +void color_correct::on_cur_val_changed(std::string& val) +{ + enable_ = val != "\xE4\xB8\x8D\xE6\xA0\xA1\xE6\xAD\xA3"; + enhance_ = val == "\xE5\xA2\x9E\xE5\xBC\xBA\xE6\xA8\xA1\xE5\xBC\x8F"; +} + +int32_t color_correct::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) +{ + if(cfg_name) + return inner_get_config(cfg_, buf, len, cfg_name, strval); + else + { + std::string val(cfg_->to_string()); + + if(*len < val.length()) + { + *len = val.length() + 4; + if(strval) + *strval = std::move(val); + + return ENOMEM; + } + + memcpy(buf, val.c_str(), val.length()); + *len = val.length(); + + return 0; + } +} +int32_t color_correct::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +{ + gb_json *child = nullptr; + int32_t ret = ENOENT; + + if(cfg_->get_value(cfg_name, child) && child) + { + sane_cfg_provider::sane_refine_range(child, data, len); + if(name_ == cfg_name) + { + std::string val((char*)data); + + on_cur_val_changed(val); + child->set_value("cur", val.c_str()); + child->release(); + } + } + + return ret; +} +void color_correct::update_enabled(std::function get_opt) +{} +int32_t color_correct::get_value(const char* name, const char* key, std::string& val) +{ + gb_json *child = nullptr; + int32_t ret = ENOENT; + + if(cfg_->get_value(name, child) && child) + { + sane_cfg_provider::raw_value_in_json(child, key, val); + child->release(); + } + + return ret; +} +img_one_paper* color_correct::execute(img_one_paper* img) +{ + if(enable_) + { + + for(auto& v: img->images_queue()) + { + correctColor(v.img, enhance_); + } + } + img->add_ref(); + + return img; +} +bool color_correct::is_enabled(std::function get_opt_value) +{ + return enable_; +} + + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class img_resizer +// { +// "resolution": { +// "category": "base", +// "readonly": false, +// "visible": true, +// "field": "Common", +// "pos": 0, +// "unit": "DPI", +// "ver": 1, +// "title": "分辨率", +// "desc": "设置扫描图像的分辨率", +// "type": "int", +// "cur": 200, +// "default": 200, +// "size": 4, +// "range": { +// "min": 100, +// "max": 600, +// "step": 50 +// } +// } +// } +static std::string resize_json = + "{\"resolution\":{\"category\":\"base\",\"readonly\":false,\"visible\":true,\"field\":\"imgproc\",\"group\":\"CIS\",\"pos\":200,\"unit\":\"DPI\",\"ver\":1,\"title\":\"\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u8bbe\\u7f6e\\u626b\\u63cf\\u56fe\\u50cf\\u7684\\u5206\\u8fa8\\u7387\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":{\"min\":100,\"max\":600,\"step\":50}}}"; + +img_resizer::img_resizer() : dpi_(200), enable_(false) +{ + name_ = "resolution"; + cfg_ = new gb_json(); + cfg_->attach_text(&resize_json[0]); + + gb_json* child = nullptr; + + if(cfg_->get_value(name_.c_str(), child) && child) + { + child->get_value("cur", dpi_); + child->get_value("ver", ver_); + child->get_value("pos", pos_); + child->release(); + } +} +img_resizer::~img_resizer() +{ + cfg_->release(); +} + +int32_t img_resizer::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) +{ + if(cfg_name) + return inner_get_config(cfg_, buf, len, cfg_name, strval); + else + { + std::string val(cfg_->to_string()); + + if(*len < val.length()) + { + *len = val.length() + 4; + if(strval) + *strval = std::move(val); + + return ENOMEM; + } + + memcpy(buf, val.c_str(), val.length()); + *len = val.length(); + + return 0; + } +} +int32_t img_resizer::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +{ + gb_json *child = nullptr; + int32_t ret = ENOENT; + + if(cfg_->get_value(cfg_name, child) && child) + { + sane_cfg_provider::sane_refine_range(child, data, len); + if(name_ == cfg_name) + { + dpi_ = *(int*)data; + child->set_value("cur", dpi_); + child->release(); + + int x = *(int*)data, + y = x; + set_dpi(&x, &y); + enable_ = x != dpi_ || y != dpi_; + } + } + + return ret; +} +void img_resizer::update_enabled(std::function get_opt) +{} +int32_t img_resizer::get_value(const char* name, const char* key, std::string& val) +{ + gb_json *child = nullptr; + int32_t ret = ENOENT; + + if(cfg_->get_value(name, child) && child) + { + sane_cfg_provider::raw_value_in_json(child, key, val); + child->release(); + } + + return ret; +} +img_one_paper* img_resizer::execute(img_one_paper* img) +{ + if(enable_) + { + + for(auto& v: img->images_queue()) + { + double ratio_x = dpi_ * 1.0f / v.head.resolution_x, + ratio_y = dpi_ * 1.0f / v.head.resolution_y; + cv::resize(v.img, v.img, cv::Size(0,0), ratio_x, ratio_y); + } + } + img->add_ref(); + + return img; +} +bool img_resizer::is_enabled(std::function get_opt_value) +{ + return enable_; +} + + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class img_alg +// { +// "img-format": { +// "category": "base", +// "readonly": true, +// "affect": 0, +// "group": "output", +// "visible": true, +// "field": "Common", +// "pos": 0, +// "unit": "None", +// "title": "图片格式", +// "desc": "设备输出的图片文件格式", +// "type": "string", +// "cur": "JPEG", +// "default": "JPEG", +// "size": 20, +// "ver": 1, +// "range": ["JPEG", "PNG", "TIFF"] +// } +// } +static std::string fmt_json = + "{\"img-format\":{\"category\":\"base\",\"readonly\":true,\"affect\":0,\"group\":\"output\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u56fe\\u7247\\u683c\\u5f0f\",\"desc\":\"\\u8bbe\\u5907\\u8f93\\u51fa\\u7684\\u56fe\\u7247\\u6587\\u4ef6\\u683c\\u5f0f\",\"type\":\"string\",\"cur\":\"JPEG\",\"default\":\"JPEG\",\"size\":20,\"ver\":1,\"range\":[\"JPEG\",\"PNG\",\"TIFF\"]}}"; + +img_encoder::img_encoder() : fmt_("JPEG") +{ + cfg_ = new gb_json(); + if(cfg_->attach_text(&fmt_json[0])) + { + gb_json* child = nullptr; + cfg_->get_value("img-format", child); + if(child) + { + child->get_value("cur", fmt_); + child->release(); + } + } +} +img_encoder::~img_encoder() +{} + +int32_t img_encoder::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) +{ + int32_t ret = ENOENT; + + if(cfg_name) + { + ret = inner_get_config(cfg_, buf, len, cfg_name, strval); + } + else + { + std::string val(cfg_->to_string()); + + if(*len < val.length()) + { + *len = val.length() + 4; + ret = ENOMEM; + } + else + { + memcpy(buf, val.c_str(), val.length()); + *len = val.length(); + ret = 0; + } + } + + return ret; +} +int32_t img_encoder::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +{ + gb_json* child = nullptr; + int32_t ret = ENOENT; + + if(cfg_->get_value(cfg_name, child) && child) + { + ret = sane_cfg_provider::sane_refine_range(child, data, len) ? 0 : EUCLEAN; + sane_cfg_provider::sane_option_value_set(child, data); + if(afterdo) + { + int v = 0; + child->get_value("affect", v); + *afterdo = v; + } + child->release(); + + if(strcmp(cfg_name, "img-format") == 0) + fmt_ = std::string((char*)data, *len); + } + + return ret; +} +void img_encoder::update_enabled(std::function get_opt) +{} +int32_t img_encoder::get_value(const char* name, const char* key, std::string& val) +{ + gb_json* child = nullptr; + int32_t ret = ENOENT; + + if(cfg_->get_value(name, child) && child) + { + val = std::move(sane_cfg_provider::sane_option_value_get(child, key)); + child->release(); + ret = val.empty() ? ENOENT : 0; + } + + return ret; +} + +#include "imageencode.h" + +MemoryPtr img_encoder::encode(PROCIMG* img) +{ + JpegImageEncode encoder(fmt_.c_str(), img->head.resolution_x); + + if(fmt_ == "JPEG") + img->head.format = IMG_FMT_JPEG; + else if(fmt_ == "PNG") + img->head.format = IMG_FMT_PNG; + else if(fmt_ == "TIFF") + img->head.format = IMG_FMT_TIFF; + + return encoder.encode(img->img); +} diff --git a/device/gxx-linux/usb/src/async_model/img_process/algs/img_algorithm.h b/device/gxx-linux/usb/src/async_model/img_process/algs/img_algorithm.h new file mode 100644 index 0000000..5d74563 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/img_process/algs/img_algorithm.h @@ -0,0 +1,180 @@ +#pragma once + +// base definition for image algorithm +// +// created on 2023-04-18 +// + +#include +#include + + +//{ +// "multiout-type": { +// "category": "base", +// "readonly" : false, +// "affect" : 4, +// "group" : "base", +// "visible" : true, +// "field" : "ImageProc", +// "pos" : 900, +// "unit" : "None", +// "title" : "多流输出类型", +// "desc" : "选择多流输出的类型", +// "type" : "string", +// "cur" : "彩色+灰度+黑白", +// "default" : "彩色+灰度+黑白", +// "size" : 32, +// "range" : ["彩色+灰度+黑白", "彩色+灰度", "彩色+黑白", "灰度+黑白"] , +// "depend_or" : ["is-multiout==true"] +// } +//} +// +// - component exports: +// +// img_processor* load_img_processor(parameter_get*) +// void apply_img_proc(dyn_mem_ptr) +#include "imageprocess/ImageApply.h" +#include "imemory.h" +#include "common/sane_cfg.h" + +class gb_json; + +class img_one_paper : public refer +{ + std::vector imgs_; + + void clear(void); + +public: + img_one_paper(); + +protected: + ~img_one_paper(); + +public: + int init_from(void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side = PAPER_SIDE_LEFT, clr_channel cc = COLOR_CHANNEL_RGB, img_status status = IMG_STATUS_OK, bool img_new = true, bool img_over = true); + int init_from(void* data, size_t w, size_t h, LPPACKIMAGE pimg); + + std::vector& images_queue(void); +}; + +enum img_alg_type +{ + IMG_ALG_NONE = 0, + IMG_ALG_DOGEAR, + IMG_ALG_SIZE_CHECK, + IMG_ALG_FILL_HOLE, + IMG_ALG_AUTO_CROP, + IMG_ALG_BLANK, + IMG_ALG_CUSTOM_AREA, + IMG_ALG_FADE_BACK, + IMG_ALG_FILTER, + IMG_ALG_ADJUST_COLOR, + IMG_ALG_HSV_CORRECT, + IMG_ALG_REFUSE_INFLOW, + IMG_ALG_AUTO_CONTRAST, + IMG_ALG_TEXTURE_REMOVE, + IMG_ALG_SHARPEN, + IMG_ALG_ADJUST_DPI, + IMG_ALG_BW, + IMG_ALG_DETACH_NOISE, + IMG_ALG_CONCATEN, + IMG_ALG_ROTATE, +}; + +class img_alg : public sane_cfg_provider +{ +protected: + int pos_; + int ver_; + std::string name_; + +public: + img_alg(); + + static img_alg* create_image_algorithm(img_alg_type type); + +protected: + virtual ~img_alg(); + +public: + // return: 0 - success + // EINVAL - the algorithm apply to the image failed, result set into PACKIMAGE::pos::status + virtual img_one_paper* execute(img_one_paper* img) = 0; + virtual bool is_enabled(std::function get_opt_value) = 0; + + virtual uint32_t position(void); + virtual uint32_t version(void); + virtual const char* option_name(void); +}; + + +class color_correct : public img_alg +{ + gb_json* cfg_; + bool enable_; + bool enhance_; + + void on_cur_val_changed(std::string& val); + +public: + color_correct(); +protected: + ~color_correct(); + +public: + virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; + virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + virtual void update_enabled(std::function get_opt) override; + virtual int32_t get_value(const char* name, const char* key, std::string& val) override; + +public: + virtual img_one_paper* execute(img_one_paper* img) override; + virtual bool is_enabled(std::function get_opt_value) override; +}; + + +class img_resizer : public img_alg +{ + gb_json* cfg_; + int dpi_; + bool enable_; + +public: + img_resizer(); +protected: + ~img_resizer(); + +public: + virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; + virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + virtual void update_enabled(std::function get_opt) override; + virtual int32_t get_value(const char* name, const char* key, std::string& val) override; + +public: + virtual img_one_paper* execute(img_one_paper* img) override; + virtual bool is_enabled(std::function get_opt_value) override; +}; + + +class img_encoder : public sane_cfg_provider +{ + std::string fmt_; + gb_json* cfg_; + +public: + img_encoder(); +protected: + ~img_encoder(); + +public: + virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; + virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + virtual void update_enabled(std::function get_opt) override; + virtual int32_t get_value(const char* name, const char* key, std::string& val) override; + +public: + MemoryPtr encode(PROCIMG* img); +}; + diff --git a/device/gxx-linux/usb/src/async_model/img_process/cis_preproc.cpp b/device/gxx-linux/usb/src/async_model/img_process/cis_preproc.cpp new file mode 100644 index 0000000..82ec64a --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/img_process/cis_preproc.cpp @@ -0,0 +1,316 @@ +#include "cis_preproc.h" + + +#include "common/json/gb_json.h" + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// configuration text +// +//{ +// "montage": { +// "category": "base", +// "readonly" : false, +// "affect" : 3, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "val": 1, +// "pos" : 10, +// "unit" : "None", +// "title" : "ͼ��ƴ��", +// "desc" : "��CIS�ɼ���ԭʼ���ݻָ�Ϊ������ͼ��", +// "type" : "bool", +// "cur" : true, +// "default" : true, +// "size" : 4 +// }, +// "fb-split": { +// "category": "base", +// "readonly" : false, +// "affect" : 2, +// "group" : "base", +// "visible" : false, +// "field" : "cis", +// "val": 1, +// "pos" : 20, +// "unit" : "None", +// "title" : "���������", +// "desc" : "��������ϳɵ�һ��ͼƬ����ֳ�����ͷ���ͼƬ", +// "type" : "bool", +// "cur" : true, +// "default" : true, +// "size" : 4, +// "depend_and": ["montage==true"] +// } +//} + +static std::string g_cis_cfg("{\"montage\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":10,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u56fe\\u50cf\\u62fc\\u63a5\",\"desc\":\"\\u5c06CIS\\u91c7\\u96c6\\u7684\\u539f\\u59cb\\u6570\\u636e\\u6062\\u590d\\u4e3a\\u6b63\\u5e38\\u7684\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"fb-split\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"CIS\",\"visible\":false,\"field\":\"cis\",\"pos\":20,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u62c6\\u5206\\u6b63\\u53cd\\u9762\",\"desc\":\"\\u5c06\\u6b63\\u53cd\\u9762\\u5408\\u6210\\u7684\\u4e00\\u5f20\\u56fe\\u7247\\u62c6\\u5206\\u6210\\u6b63\\u9762\\u548c\\u53cd\\u9762\\u56fe\\u7247\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4}}"); + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class cis_pre_do +#ifdef TEMPORARY_API +#include "../capimage/hgutils.h" + +img_one_paper* cis_montager(img_one_paper* in) +{ + for(auto& v: in->images_queue()) + { + // 0x00090002 GetMergeMat(int dstwidth ,int dstheight,int type,cv::Mat& mat,unsigned int fpgaversion) + v.img = GetMergeMat(v.head.width * v.head.channels, v.head.height, v.head.channels == 1 ? CV_8UC1 : CV_8UC3, v.img, 0x00090001); + v.head.width = v.img.cols; + v.head.height = v.img.rows; + } + in->add_ref(); + + return in; +} +img_one_paper* cis_spliter(img_one_paper* in) +{ + std::vector result; + + for(auto& v: in->images_queue()) + { + if(v.head.pos.paper_side == PAPER_SIDE_LEFT) + { + int actwidth = v.img.cols / 2; + int actheight = v.img.rows; + for (int i = 0; i < 2; i++) + { + PROCIMG ii; + ii.img = v.img(cv::Rect(i * actwidth, 0, actwidth, actheight)); + if (!ii.img.empty()) + { + memcpy(&ii.head, &v.head, sizeof(ii.head)); + ii.head.width = v.img.cols; + ii.head.height = v.img.rows; + ii.head.pos.paper_side = i == 0 ? PAPER_SIDE_FRONT : PAPER_SIDE_BACK; + + result.push_back(ii); + } + } + } + } + if(result.size()) + in->images_queue() = std::move(result); + + in->add_ref(); + + return in; +} + +#endif + +cis_pre_do::cis_pre_do(std::function montage + , std::function< img_one_paper* (img_one_paper*)> split) + : montage_(montage), split_(split) + , cfg_(g_cis_cfg), is_montage_(true), is_split_(true) +{ + if (!montage_) + montage_ = cis_montager; + if (!split_) + split_ = cis_spliter; + + init_value(); +} +cis_pre_do::~cis_pre_do() +{} + +gb_json* cis_pre_do::from_json_text(char* jsn_text) +{ + gb_json* jsn = new gb_json(); + + if (!jsn_text) + jsn_text = &cfg_[0]; + + if (!jsn->attach_text(jsn_text)) + { + jsn->release(); + jsn = nullptr; + } + + return jsn; +} +void cis_pre_do::init_value(void) +{ + gb_json* jsn = from_json_text(&cfg_[0]); + + if (jsn) + { + gb_json* child = nullptr; + + if (jsn->get_value("montage", child) && child) + { + if (!child->get_value("cur", is_montage_)) + is_montage_ = true; + child->release(); + } + if (jsn->get_value("fb-split", child) && child) + { + if (!child->get_value("cur", is_split_)) + is_split_ = true; + child->release(); + } + jsn->release(); + } +} + +int32_t cis_pre_do::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) +{ + gb_json* jsn = from_json_text(&cfg_[0]); + int ret = ENOENT; + + if (jsn) + { + ret = inner_get_config(jsn, buf, len, cfg_name, strval); + jsn->release(); + } + + return ret; +} +int32_t cis_pre_do::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +{ + int ret = ENOENT; + gb_json* root = from_json_text(), *child = nullptr; + + if (root) + { + if (root->get_value(cfg_name, child) && child) + { + ret = sane_cfg_provider::sane_refine_range(child, data, len) ? 0 : EUCLEAN; + sane_cfg_provider::sane_option_value_set(child, data); + if(afterdo) + { + int v = 0; + child->get_value("affect", v); + *afterdo = v; + } + child->release(); + cfg_ = root->to_string(); + init_value(); + } + + root->release(); + } + + return ret; +} +void cis_pre_do::update_enabled(std::function get_opt) +{ + gb_json* root = new gb_json(); + + if(root->attach_text(&cfg_[0])) + { + sane_cfg_provider::update_option_enable_status(root, get_opt); + cfg_ = std::move(root->to_string()); + } + + root->release(); +} +int32_t cis_pre_do::get_value(const char* name, const char* key, std::string& val) +{ + gb_json* root = new gb_json(), *child = nullptr; + int32_t ret = ENOENT; + + if(root->attach_text(&cfg_[0])) + { + if(root->get_value(name, child) && child) + { + if(sane_cfg_provider::raw_value_in_json(child, key, val)) + ret = 0; + child->release(); + } + } + root->release(); + + return ret; +} + +img_one_paper* cis_pre_do::execute(img_one_paper* img) +{ + img->add_ref(); + + if(is_montage_) + { + printf("montage ...\n"); + img_one_paper* mont = montage_(img); + img->release(); + img = mont; + } + if(is_split_) + { + printf("split ...\n"); + img_one_paper* sp = split_(img); + img->release(); + img = sp; + } + + return img; +} + +// void cis_pre_do::pre_do(std::function put, void* data, size_t w, size_t h, size_t paper_ind, img_status status, bool img_new, bool img_over) +// { +// img_one_paper* img = new img_one_paper(); +// PACKIMAGE pkimg; + +// memset(&pkimg, 0, sizeof(pkimg)); +// pkimg.pos.new_img = img_new; +// pkimg.pos.img_over = img_over; +// pkimg.pos.paper_ind = paper_ind; +// pkimg.pos.paper_side = side_; +// pkimg.pos.status = status; +// pkimg.resolution_x = dpi_x_; +// pkimg.resolution_y = dpi_y_; +// if (clr_ == COLOR_CHANNEL_RGBA) +// pkimg.channels = 4; +// else if (clr_ == COLOR_CHANNEL_RGB) +// pkimg.channels = 3; +// else +// pkimg.channels = 1; +// pkimg.bpp = 8; +// pkimg.data_size = w * h; +// pkimg.format = IMG_FMT_BMP; +// pkimg.width = w / pkimg.channels; +// pkimg.height = h; +// pkimg.bppc = pkimg.channels * pkimg.bpp; +// if (img->init_from(data, w, h, &pkimg) == 0) +// { +// std::vector imgs; + +// if (is_montage_) +// { +// // do montage ... +// img_one_paper* mont = montage_(img); + +// img->release(); +// img = nullptr; + +// // split ? +// if (is_split_) +// { +// img_one_paper* back = nullptr, +// *front = split_(mont, &back); +// mont->release(); +// imgs.push_back(front); +// imgs.push_back(back); +// } +// else +// imgs.push_back(mont); +// } +// else +// { +// imgs.push_back(img); +// img = nullptr; +// } + +// for (auto& v : imgs) +// { +// put(v); +// v->release(); +// } +// imgs.clear(); +// } + +// if(img) +// img->release(); +// } diff --git a/device/gxx-linux/usb/src/async_model/img_process/cis_preproc.h b/device/gxx-linux/usb/src/async_model/img_process/cis_preproc.h new file mode 100644 index 0000000..5d6cb0f --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/img_process/cis_preproc.h @@ -0,0 +1,40 @@ +#pragma once + +// CIS pre-processor, to transform raw data from CIS to front & back image +// +// created on 2023-04-18 +// + +#include "./algs/img_algorithm.h" +#include + +class gb_json; + +class cis_pre_do : public sane_cfg_provider +{ + std::string cfg_; + bool is_montage_; + bool is_split_; + + std::function montage_; + std::function split_; + + gb_json* from_json_text(char* jsn_text = nullptr); + void init_value(void); + +public: + cis_pre_do(std::function montage = std::function() + , std::function split = std::function()); + +protected: + ~cis_pre_do(); + +public: + virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; + virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + virtual void update_enabled(std::function get_opt) override; + virtual int32_t get_value(const char* name, const char* key, std::string& val) override; + +public: + img_one_paper* execute(img_one_paper* img); +}; diff --git a/device/gxx-linux/usb/src/async_model/img_process/img_process.cpp b/device/gxx-linux/usb/src/async_model/img_process/img_process.cpp new file mode 100644 index 0000000..0e570e3 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/img_process/img_process.cpp @@ -0,0 +1,388 @@ +#include "img_process.h" + +#include +#include "common/json/gb_json.h" +#include "img_process/algs/img_algorithm.h" + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// + + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class img_processor + +img_processor::img_processor(std::function img_sender + , std::function get_opt) + : img_sender_(img_sender), get_opt_val_(get_opt), speed_first_(true), run_(true) + , scan_staus_(0), busy_cnt_(0) +{ + cis_pre_ = new cis_pre_do(); + encoder_ = new img_encoder(); + + load_processors(); + worker_ = new thread_pool(this); + worker_->thread_new(&img_processor::worker_thread, true); +} +img_processor::~img_processor() +{ + stop(); + worker_->thread_stop(); + worker_->release(); + cis_pre_->release(); + encoder_->release(); + + clear_processors(); +} + + bool img_processor::compare_img_processors_position(img_alg* l, img_alg* r) + { + return l->position() < r->position(); + } + +void img_processor::add_to_json(gb_json* root, sane_cfg_provider* cfg, void** buf, size_t* len) +{ + size_t l = *len; + char* mem = (char*)*buf; + int32_t ret = cfg->get_config(mem, &l); + + if(ret == ENOMEM) + { + l += 31; + l /= 16; + l *= 16; + delete[] mem; + mem = new char[l]; + memset(mem, 0, l); + + *len = l; + *buf = mem; + ret = cfg->get_config(mem, &l); + } + + if(ret == 0) + { + gb_json* jsn = new gb_json(), *child = nullptr; + if(jsn->attach_text(mem)) + { + child = jsn->first_child(); + while(child) + { + root->set_value(child->key().c_str(), child); + child->release(); + child = jsn->next_child(); + } + } + jsn->release(); + } +} +void img_processor::clear_processors(void) +{ + for(auto& v: all_proc_) + v->release(); + all_proc_.clear(); + + for(auto& v: cur_proc_) + v->release(); + cur_proc_.clear(); +} +void img_processor::load_processors(void) +{ + img_alg* alg = nullptr; + + clear_processors(); + +#define CREATE_ALG(type) \ + alg = img_alg::create_image_algorithm(type); \ + if(alg) \ + all_proc_.push_back(alg); + + CREATE_ALG(IMG_ALG_DOGEAR); + CREATE_ALG(IMG_ALG_SIZE_CHECK); + CREATE_ALG(IMG_ALG_FILL_HOLE); + CREATE_ALG(IMG_ALG_AUTO_CROP); + CREATE_ALG(IMG_ALG_BLANK); + CREATE_ALG(IMG_ALG_CUSTOM_AREA); + CREATE_ALG(IMG_ALG_FADE_BACK); + CREATE_ALG(IMG_ALG_FILTER); + CREATE_ALG(IMG_ALG_ADJUST_COLOR); + CREATE_ALG(IMG_ALG_HSV_CORRECT); + CREATE_ALG(IMG_ALG_REFUSE_INFLOW); + CREATE_ALG(IMG_ALG_AUTO_CONTRAST); + CREATE_ALG(IMG_ALG_TEXTURE_REMOVE); + CREATE_ALG(IMG_ALG_SHARPEN); + CREATE_ALG(IMG_ALG_ADJUST_DPI); + CREATE_ALG(IMG_ALG_BW); + CREATE_ALG(IMG_ALG_DETACH_NOISE); + CREATE_ALG(IMG_ALG_CONCATEN); + CREATE_ALG(IMG_ALG_ROTATE); + + reorder_processors(); +} +void img_processor::reorder_processors(void) +{ + // first, discard lower version of the same option name ... + for(int i = 0; i < (int)all_proc_.size() - 1; ++i) + { + for(int j = i + 1; j < (int)all_proc_.size(); ++j) + { + if(strcmp(all_proc_[i]->option_name(), all_proc_[j]->option_name()) == 0) + { + if(all_proc_[i]->version() < all_proc_[j]->version()) + { + all_proc_[i]->release(); + all_proc_[i] = all_proc_[j]; + } + else + { + all_proc_[j]->release(); + } + all_proc_.erase(all_proc_.begin() + j); + j--; + } + } + } + + // last, push active processors + reload_cur_processors(); +} +void img_processor::reload_cur_processors(void) +{ + for(auto& v: cur_proc_) + v->release(); + cur_proc_.clear(); + + for(auto& v : all_proc_) + { + if(v->is_enabled(get_opt_val_)) + { + v->add_ref(); + cur_proc_.push_back(v); + } + } + + std::sort(cur_proc_.begin(), cur_proc_.end(), img_processor::compare_img_processors_position); +} + +uint32_t img_processor::add_busy_count(int adden) +{ + std::lock_guard lock(cnt_lock_); + + busy_cnt_ += adden; + + return busy_cnt_; +} +void img_processor::worker_thread(bool first) +{ + while(run_) + { + if(!first && !speed_first_) + { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + continue; + } + + img_one_paper* img = nullptr; + if(img_que_.take(img, true)) + { + if(img) + { + add_busy_count(); + handle_image(img); + add_busy_count(-1); + + // img->release(); // release in 'handle_image' + } + else + { + while(add_busy_count(0)) + std::this_thread::sleep_for(std::chrono::microseconds(50)); + + img_sender_(nullptr, nullptr, nullptr, scan_staus_); + } + } + } +} +void img_processor::handle_image(img_one_paper* img) +{ + img_one_paper* doing = nullptr; + + // img->add_ref(); // release it right now + + // CIS pre-do ... + doing = cis_pre_->execute(img); + img->release(); + img = doing; + + // image process ... + for(auto& v: cur_proc_) + { + doing = v->execute(img); + + img->release(); + img = doing; + } + + // encode/compress ... + for(auto& v: img->images_queue()) + { + MemoryPtr imgf = encoder_->encode(&v); + + img_sender_(&v.head, imgf, v.info.c_str(), v.info.length()); + } + img->release(); +} + +int32_t img_processor::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) +{ + int32_t ret = 0; + + if (!len) + return EINVAL; + + if (cfg_name) + { + ret = cis_pre_->get_config(buf, len, cfg_name, strval); + if(ret == ENOENT) + { ret = encoder_->get_config(buf, len, cfg_name, strval); + if(ret == ENOENT) + { + for(auto& v : all_proc_) + { + ret = v->get_config(buf, len, cfg_name, strval); + if(ret != ENOENT) + break; + } + } + } + } + else + { + gb_json* root = new gb_json("{}"); + size_t size = 2 * 1024, + bufl = size; + char* mem = new char[size]; + std::string val(""); + + add_to_json(root, dynamic_cast(cis_pre_), (void**)&mem, &bufl); + for(auto& v: all_proc_) + add_to_json(root, dynamic_cast(v), (void**)&mem, &bufl); + add_to_json(root, dynamic_cast(encoder_), (void**)&mem, &bufl); + + val = root->to_string(); + root->release(); + delete[] mem; + { + if (*len < val.length()) + { + *len = val.length() + 4; + ret = ENOMEM; + } + else + { + memcpy(buf, val.c_str(), val.length()); + *len = val.length(); + } + } + } + + return ret; +} +int32_t img_processor::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +{ + int ret = cis_pre_->set_config(cfg_name, data, len, afterdo); + + if(ret == ENOENT) + { + ret = encoder_->set_config(cfg_name, data, len, afterdo); + if(ret == ENOENT) + { + for(auto& v: all_proc_) + { + ret = v->set_config(cfg_name, data, len, afterdo); + if(ret != ENOENT) + { + reload_cur_processors(); + break; + } + } + } + } + + return ret; +} +void img_processor::update_enabled(std::function get_opt) +{ + // sane_cfg_provider::update_option_enable_status(cfg_, get_opt); + cis_pre_->update_enabled(get_opt); + for(auto& v: all_proc_) + { + v->update_enabled(get_opt); + } + reload_cur_processors(); + encoder_->update_enabled(get_opt); +} +int32_t img_processor::get_value(const char* name, const char* key, std::string& val) +{ + int32_t ret = cis_pre_->get_value(name, key, val); + + if(ret == ENOENT) + { + ret = encoder_->get_value(name, key, val); + if(ret == ENOENT) + { + for(auto& v: all_proc_) + { + ret = v->get_value(name, key, val); + if(ret != ENOENT) + break; + } + } + } + + return ret; +} + +int32_t img_processor::push_image(img_one_paper* img, bool over) +{ + if(run_) + { + if(over) + { + scan_staus_ = (uint32_t)(uint64_t)img; + img_que_.save(nullptr, true); + } + else + { + img->add_ref(); + + size_t cnt = img_que_.save(img, true); + + if(speed_first_ && cnt >= 4 && worker_->count() < 3) + worker_->thread_new(&img_processor::worker_thread, false); + } + } + + return 0; +} +int32_t img_processor::stop(void) +{ + run_ = false; + for(size_t i = 0; i < worker_->count(); ++i) + img_que_.quit(); + + return 0; +} +int32_t img_processor::set_speed_first(bool first) +{ + speed_first_ = first; + + return 0; +} +int32_t img_processor::que_size(void) +{ + return img_que_.size(); +} diff --git a/device/gxx-linux/usb/src/async_model/img_process/img_process.h b/device/gxx-linux/usb/src/async_model/img_process/img_process.h new file mode 100644 index 0000000..e4f42a1 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/img_process/img_process.h @@ -0,0 +1,74 @@ +#pragma once + +// image process interface classes +// +// created on 2022-12-14 +// + +#include "common/referer.h" +#include "common/packet.h" +#include "common/sane_cfg.h" +#include "cis_preproc.h" +#include "common/ipc_util.h" +#include +#include +#include "imemory.h" + +#define IMG_SENDER_PROTO void(LPPACKIMAGE /*image head, nullptr for scan over*/, MemoryPtr /*image data, nullptr for scan over*/, const void* /*image info*/, size_t/*image info bytes, scanner status for scan over*/) + +class img_alg; +class img_encoder; +class cis_pre_do; +class gb_json; + +class img_processor : public sane_cfg_provider +{ + std::function img_sender_; + std::function get_opt_val_; + + std::vector all_proc_; + + cis_pre_do* cis_pre_; + std::vector cur_proc_; + img_encoder* encoder_; + + safe_fifo img_que_; + thread_pool* worker_; + volatile bool speed_first_; + volatile bool run_; + uint32_t scan_staus_; + uint32_t busy_cnt_; + std::mutex cnt_lock_; + + static bool compare_img_processors_position(img_alg* l, img_alg* r); + + void add_to_json(gb_json* root, sane_cfg_provider* cfg, void** buf, size_t* len); + void clear_processors(void); + void load_processors(void); + void reorder_processors(void); + void reload_cur_processors(void); + + uint32_t add_busy_count(int adden = 1); + void worker_thread(bool first); + void handle_image(img_one_paper* img); + +public: + img_processor(std::function img_sender, std::function get_opt); + +protected: + ~img_processor(); + + // sane_cfg_provider +public: + virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; + virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + virtual void update_enabled(std::function get_opt) override; + virtual int32_t get_value(const char* name, const char* key, std::string& val) override; + +public: + int32_t push_image(img_one_paper* img/*scan status if 'over' was true*/, bool over = false); + int32_t stop(void); + int32_t set_speed_first(bool first); // start as many threads as possible if 'first' was true, or down to ONE thread + int32_t que_size(void); +}; + diff --git a/device/gxx-linux/usb/src/common/data.cpp b/device/gxx-linux/usb/src/async_model/io/data.cpp similarity index 99% rename from device/gxx-linux/usb/src/common/data.cpp rename to device/gxx-linux/usb/src/async_model/io/data.cpp index 3a8f2d1..5fa5ec4 100644 --- a/device/gxx-linux/usb/src/common/data.cpp +++ b/device/gxx-linux/usb/src/async_model/io/data.cpp @@ -43,7 +43,7 @@ namespace sys_util } } #else -#include "sys_util.h" +#include "common/sys_util.h" #include #include #endif diff --git a/device/gxx-linux/usb/src/common/data.h b/device/gxx-linux/usb/src/async_model/io/data.h similarity index 94% rename from device/gxx-linux/usb/src/common/data.h rename to device/gxx-linux/usb/src/async_model/io/data.h index 993de72..6ec9e89 100644 --- a/device/gxx-linux/usb/src/common/data.h +++ b/device/gxx-linux/usb/src/async_model/io/data.h @@ -4,8 +4,8 @@ // // created on 2023-03-10 -#include "referer.h" -#include "packet.h" +#include "common/referer.h" +#include "common/packet.h" #include #include @@ -13,12 +13,11 @@ #define CLS_PTR(cls) typedef cls* cls##_ptr; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // /* packet parameter keeper, parameter of corresponding packet */ -#define PROGRESS_NOTIFYER std::function +#define PROGRESS_NOTIFYER std::function class packet_data_base : public refer { @@ -215,7 +214,7 @@ CLS_PTR(file_reader); // // dyn_mem_ptr - the packet buffer, read-only // -// uint32_t* - to return how many data in bytes the handler consumed +// uint32_t* - to return how many data in bytes the handler consumed, the most high bit is to indicate whether should notify the returned packet has sent // // normally, the value should be sizeof(PACK_BASE) + PACK_BASE::payload_len, i.e. the handler consume all data of an entire packet // @@ -229,5 +228,7 @@ CLS_PTR(file_reader); // // return value of all routines is the reply packet, nullptr if the packet need not reply // +// NOTE: when parameter uint32_t* and packet_data_base_ptr* both are nullptr, it is notifying the command reply packet has sent, callback should return nullptr only +// #define FUNCTION_PROTO_COMMAND_HANDLE dyn_mem_ptr(dyn_mem_ptr, uint32_t* /*used*/, packet_data_base_ptr* /*The number of bytes required for this packet, 0 is over for this packet*/) diff --git a/device/gxx-linux/usb/src/async_model/io/sent_img.cpp b/device/gxx-linux/usb/src/async_model/io/sent_img.cpp new file mode 100644 index 0000000..4e27051 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/io/sent_img.cpp @@ -0,0 +1,110 @@ +#include "sent_img.h" + +#include "common/sys_util.h" +#include "common/log_util.h" + +// C2-B0-AF-79-75-D6 +// + + +image_packet::image_packet(LPPACKIMAGE head, MemoryPtr img, uint32_t scanid, uint32_t sn, const void* info, size_t info_size) + : img_(img), offset_(0), sn_(sn), info_over_(false) +{ + LPPACK_BASE pack = nullptr; + LPPACKIMAGE pimg = nullptr; + + if(info && info_size) + info_ = std::string((const char*)info, info_size); + else + info_ = ""; + + head_ = dyn_mem::memory(sizeof(PACK_BASE) + sizeof(PACKIMAGE)); + pack = (LPPACK_BASE)head_->ptr(); + pimg = (LPPACKIMAGE)pack->payload; + BASE_PACKET_REPLY(*pack, PACK_CMD_SCAN_IMG_ROGER, scanid, 0); + pack->payload_len = sizeof(PACKIMAGE); + + memcpy(pimg, head, sizeof(*pimg)); + pimg->data_size = img->size(); + pimg->info_size = info_size; + + head_->set_len(sizeof(PACK_BASE) + sizeof(PACKIMAGE)); + info_over_ = info_.empty(); + + log_cls::log(LOG_LEVEL_ALL, "Image-%04u wait to be sent: size = %u\n", sn_, img->size() + info_.length()); +} +image_packet::~image_packet() +{ + uint32_t size = img_->size(); + + head_->release(); + img_.reset(); + log_cls::log(LOG_LEVEL_ALL, "Image-%04u sending complete: %u/%u\n", sn_, offset_, size); +} + +bool image_packet::is_memory_block(void) +{ + return false; +} +uint32_t image_packet::get_rest(void) +{ + return head_->get_rest() + info_.length() + img_->size() - offset_; +} + +// following API valid when is_memory_block() return true +uint8_t* image_packet::ptr(void) +{ + return nullptr; +} + +// following API valid when is_memory_block() return false. return error code +int image_packet::fetch_data(void* buf, uint32_t* size) +{ + if(head_->get_rest()) + { + if(*size < head_->get_rest()) + { + memcpy(buf, head_->ptr(), *size); + } + else + { + memcpy(buf, head_->ptr(), head_->get_rest()); + *size = head_->get_rest(); + } + head_->used(*size); + } + else if(!info_over_) + { + if(*size < info_.length() - offset_) + { + memcpy(buf, info_.c_str() + offset_, *size); + offset_ += *size; + } + else + { + memcpy(buf, info_.c_str() + offset_, info_.length() - offset_); + *size = info_.length() - offset_; + + info_over_ = true; + info_ = ""; + offset_ = 0; + } + } + else + { + if(*size + offset_ >= img_->size()) + { + memcpy(buf, img_->data() + offset_, img_->size() - offset_); + *size = img_->size() - offset_; + offset_ = img_->size(); + } + else + { + memcpy(buf, img_->data() + offset_, *size); + offset_ += *size; + } + } + + return 0; +} + diff --git a/device/gxx-linux/usb/src/async_model/io/sent_img.h b/device/gxx-linux/usb/src/async_model/io/sent_img.h new file mode 100644 index 0000000..c59856b --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/io/sent_img.h @@ -0,0 +1,34 @@ +// readonly options +// +// 2023-04-26 + +#pragma once + +#include "data.h" +#include "imemory.h" + +class image_packet : public data_source +{ + MemoryPtr img_; + dyn_mem_ptr head_; + uint32_t offset_; + uint32_t sn_; + std::string info_; + bool info_over_; + +public: + image_packet(LPPACKIMAGE head, MemoryPtr img, uint32_t scanid, uint32_t sn, const void* info = nullptr, size_t info_size = 0); + +protected: + virtual ~image_packet(); + +public: + virtual bool is_memory_block(void) override; + virtual uint32_t get_rest(void) override; + + // following API valid when is_memory_block() return true + virtual uint8_t* ptr(void) override; + + // following API valid when is_memory_block() return false. return error code + virtual int fetch_data(void* buf, uint32_t* size) override; +}; diff --git a/device/gxx-linux/usb/src/common/usb_io.cpp b/device/gxx-linux/usb/src/async_model/io/usb_io.cpp similarity index 98% rename from device/gxx-linux/usb/src/common/usb_io.cpp rename to device/gxx-linux/usb/src/async_model/io/usb_io.cpp index 953bb11..6c12d28 100644 --- a/device/gxx-linux/usb/src/common/usb_io.cpp +++ b/device/gxx-linux/usb/src/async_model/io/usb_io.cpp @@ -5,9 +5,9 @@ #include #include #include "../../inc/logs_out.h" -#include "sys_util.h" -#include "log_util.h" -#include "encrypt.h" +#include "common/sys_util.h" +#include "common/log_util.h" +#include "common/encrypt.h" // #define TEST @@ -704,6 +704,7 @@ void async_usb_gadget::thread_pump_task(void) { packet_data_base_ptr pack_data = nullptr; data_source_ptr ds = nullptr; + bool notify_reply_ok = false; if(dh == nullptr) { @@ -716,6 +717,8 @@ void async_usb_gadget::thread_pump_task(void) status_.task_pack_id = pack->pack_id; used = data->get_rest(); reply = handle_bulk_command(data, &used, &pack_data); + notify_reply_ok = used & (INT32_MAX + 1); + used &= INT32_MAX; if(pack_data) { dh = dynamic_cast(pack_data); @@ -788,6 +791,8 @@ void async_usb_gadget::thread_pump_task(void) } write_bulk(dynamic_cast(reply)); + if(notify_reply_ok) + handle_bulk_command(data, nullptr, nullptr); reply->release(); reply = nullptr; } diff --git a/device/gxx-linux/usb/src/common/usb_io.h b/device/gxx-linux/usb/src/async_model/io/usb_io.h similarity index 97% rename from device/gxx-linux/usb/src/common/usb_io.h rename to device/gxx-linux/usb/src/async_model/io/usb_io.h index 4f30379..a996e54 100644 --- a/device/gxx-linux/usb/src/common/usb_io.h +++ b/device/gxx-linux/usb/src/async_model/io/usb_io.h @@ -4,16 +4,16 @@ // // created on 2023-03-10 -#include "referer.h" -#include "packet.h" -#include "ipc_util.h" +#include "common/referer.h" +#include "common/packet.h" +#include "common/ipc_util.h" #include "data.h" #include #include #include #include -#include "../../inc/usb_gadget.h" +#include "inc/usb_gadget.h" // callback proto diff --git a/device/gxx-linux/usb/src/async_model/scanner/async_scanner.cpp b/device/gxx-linux/usb/src/async_model/scanner/async_scanner.cpp new file mode 100644 index 0000000..d075ae2 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/scanner/async_scanner.cpp @@ -0,0 +1,841 @@ +#include "async_scanner.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/log_util.h" +#include "common/sys_util.h" +#include "common/json/gb_json.h" +#include "common/sane_cfg.h" +#include "hardware/hardware.h" +#include "img_process/img_process.h" +#include "io/usb_io.h" +#include "io/sent_img.h" +#include "readonly_opts.h" + + +#ifdef TEMPORARY_API +extern int32_t (*scan_start)(void); +extern int32_t (*scan_stop)(void); +extern int32_t (*set_dpi)(int*, int*); +extern int32_t (*set_scan_num)(int); +extern int32_t (*set_image_receiver)(void(*rcv)(int data_type, void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel clr, img_status status, bool img_new, bool img_over, void* param), void* param); + +static bool reg_img_cb = true; +static void push_image(int data_type, void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel clr, img_status status, bool img_new, bool img_over, void* param) +{ + ((async_scanner*)param)->push_image(data_type, data, w, h, dpi_x, dpi_y, paper_ind, side, clr, status, img_new, img_over); +} +#endif + + + +static void dump_buf(uint8_t *data, int len) +{ + uint32_t addr = 0; + std::string cont(""), asc(""); + char buf[20] = { 0 }; + for(int i = 0; i < len; ++i) + { + if((i % 16) == 0) + { + if (cont.length()) + log_cls::log(LOG_LEVEL_ALL, "%s %s\n", cont.c_str(), asc.c_str()); + sprintf(buf, "0x%08x ", addr); + addr += 16; + cont = buf; + asc = ""; + } + else if((i % 8) == 0) + { + cont += " "; + } + + uint8_t v = data[i]; + sprintf(buf, "%02X ", v); + cont += buf; + if(v >= 0x20 && v < 0x7f) + asc.append(1, v); + else + asc += "."; + } + if(asc.length()) + { + std::string pad(" "); + if(asc.length() <= 8) + pad.erase((16 - asc.length()) * 3 + 2); + else if(asc.length() < 16) + pad.erase((16 - asc.length()) * 3); + else + pad = ""; + log_cls::log(LOG_LEVEL_ALL, "%s%s %s\n", cont.c_str(), pad.c_str(), asc.c_str()); + } +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +async_scanner::async_scanner(usb_gadget* gadget) : usb_(nullptr), cfg_mgr_(nullptr), scan_id_(0) +{ + log_cls::initialize(nullptr); + init(); + + auto bulk_handle = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* required) -> dyn_mem_ptr + { + LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); + + if(used) + *used = data->get_rest(); + + return handle_bulk_cmd(pack, used, required); + }; + auto ctrl_unhandle = [&](struct usb_functionfs_event* pev) -> dyn_mem_ptr + { + return unhandled_ep0(pev); + }; + auto on_connect = [&](bool connected) -> void + { + log_cls::log(LOG_LEVEL_ALL, "USB %s\n", connected ? "connected" : "dis-connected"); + }; + usb_ = new async_usb_gadget(gadget, ctrl_unhandle, bulk_handle, on_connect); +} + +async_scanner::~async_scanner() +{ + if(usb_) + { + usb_->stop(); + usb_->release(); + } + if(cfg_mgr_) + cfg_mgr_->release(); +} + +void async_scanner::push_image(int data_type, void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel clr, img_status status, bool img_new, bool img_over) +{ + if(data_type == IMG_CB_STOPPED) + { + if(w == 0) + w = scan_err_; + img_prc_->push_image((img_one_paper*)w, true); + } + else if(data_type == IMG_CB_STATUS) + { + if(scan_id_ == 0) + { + dyn_mem_ptr reply = dyn_mem::memory(sizeof(PACK_BASE)); + BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), PACK_CMD_STATUS_ROGER, 0, w); + reply->set_len(sizeof(PACK_BASE)); + usb_->write_bulk(reply); + reply->release(); + } + else + { + scan_err_ = w; + } + } + else if(data) + { + img_one_paper *paper = new img_one_paper(); + + paper->init_from(data, w, h, dpi_x, dpi_y, paper_ind, side, clr, status, img_new, img_over); + img_prc_->push_image(paper); + paper->release(); + + // paper count ... + dyn_mem_ptr reply = dyn_mem::memory(sizeof(PACK_BASE)); + BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), PACK_CMD_SCAN_PAPER_ROGER, scan_id_, paper_ind); + reply->set_len(sizeof(PACK_BASE)); + usb_->write_bulk(reply); + reply->release(); + } +} + + +dyn_mem_ptr async_scanner::unhandled_ep0(struct usb_functionfs_event* pev) +{ + return nullptr; +} +dyn_mem_ptr async_scanner::handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + dyn_mem_ptr reply = nullptr; + LPPACK_BASE pk = nullptr; + size_t base_head_size = sizeof(PACK_BASE); + + if(pack->size != base_head_size) + { + if(used) + { + log_cls::log(LOG_LEVEL_ALL, "Unknown Packet with %d bytes:\n", *used); + dump_buf((uint8_t*)pack, *used); + } + reply = dyn_mem::memory(base_head_size); + LPPACK_BASE p = (LPPACK_BASE)reply->ptr(); + BASE_PACKET_REPLY(*p, PACK_CMD_INVALID, pack->pack_id, pack->cmd); + reply->set_len(base_head_size); + + return reply; + } + + switch(pack->cmd) + { + case PACK_CMD_SYNC: + reply = handle_simple_roger(pack, used, required); + break; + case PACK_CMD_SETTING_GET_CUR: + reply = handle_get_opt_value(pack, used, required); + break; + case PACK_CMD_SETTING_GET: + reply = handle_get_opt_all(pack, used, required); + break; + case PACK_CMD_SETTING_SET: + reply = handle_set_opt(pack, used, required); + break; + case PACK_CMD_FILE_WRITE_REQ: + reply = handle_file_receive(pack, used, required); + break; + case PACK_CMD_FILE_READ_REQ: + reply = handle_file_send(pack, used, required); + break; + case PACK_CMD_SCAN_START: + reply = handle_scan_start(pack, used, required); + break; + case PACK_CMD_SCAN_STOP: + reply = handle_scan_stop(pack, used, required); + break; + default: + log_cls::log(LOG_LEVEL_ALL, "Unhandled Packet with command %d:\n", pack->cmd); + if(used) + { + dump_buf((uint8_t*)pack, *used); + } + reply = dyn_mem::memory(base_head_size); + LPPACK_BASE p = (LPPACK_BASE)reply->ptr(); + BASE_PACKET_REPLY(*p, pack->cmd + 1, pack->pack_id, EINVAL); + reply->set_len(base_head_size); + break; + } + + return reply; +} +void async_scanner::init(void) +{ + readonly_cfg* r = new readonly_cfg(); + cfg_mgr_ = new sane_cfg_mgr(); + cfg_mgr_->reg_sane_provider(dynamic_cast(r)); + r->release(); + + auto send_img = [&](LPPACKIMAGE head, MemoryPtr img, const void* info, size_t info_size) -> void + { + image_packet* imgp = nullptr; + uint32_t ind = 0; + + if(head) + { + { + LOCKER lock(locker_); + + ind = ++img_cnt_; + } + + imgp = new image_packet(head, img, scan_id_, ind, info, info_size); + usb_->write_bulk(imgp); + imgp->release(); + } + else + { + int wait = 0; + dyn_mem_ptr reply = dyn_mem::memory(sizeof(PACK_BASE)); + BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), PACK_CMD_SCAN_FINISHED_ROGER, scan_id_, info_size); + reply->set_len(sizeof(PACK_BASE)); + scan_id_ = 0; + while(!reply_start_ && wait++ < 200) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + usb_->write_bulk(reply); + reply->release(); + } + }; + auto get_opt = [&](const char* name, void* buf, size_t* len) -> int32_t + { + std::string val(""); + int32_t ret = cfg_mgr_->get_config(val, name); + + if(ret == 0) + { + if(*len < val.length()) + { + ret = ENOMEM; + } + else + { + memcpy(buf, val.c_str(), val.length()); + } + *len = val.length(); + } + + return ret; + }; + img_prc_ = new img_processor(send_img, get_opt); + cfg_mgr_->reg_sane_provider(dynamic_cast(img_prc_)); + + auto on_image_captured = [&](int data_type, void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel clr, img_status status, bool img_new, bool img_over) -> void + { + push_image(data_type, data, w, h, dpi_x, dpi_y, paper_ind, side, clr, status, img_new, img_over); + }; + capture_ = new image_capture(on_image_captured); + cfg_mgr_->reg_sane_provider(dynamic_cast(capture_)); +} + +dyn_mem_ptr async_scanner::handle_simple_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = dyn_mem::memory(base_head_size); + LPPACK_BASE pk = (LPPACK_BASE)reply->ptr(); + + *used = base_head_size; + BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, 0); + reply->set_len(base_head_size); + + return reply; +} +dyn_mem_ptr async_scanner::handle_get_opt_value(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = nullptr; + LPPACK_BASE pk = nullptr; + + if(*used < base_head_size + pack->payload_len) + { + *used = 0; + } + else + { + std::string val(""), str(""); + uint32_t err = cfg_mgr_->get_config(val, pack->payload, &str); + LPCFGVAL cfg = nullptr; + + log_cls::log(LOG_LEVEL_ALL, "Option '%s' value: %s\n", pack->payload, str.c_str()); + reply = dyn_mem::memory(base_head_size + sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1); + pk = (LPPACK_BASE)reply->ptr(); + BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err); + cfg = (LPCFGVAL)pk->payload; + cfg->val_size = val.length(); + cfg->val_off = 0; + cfg->name_off = val.length() + 1; + pk->payload_len = sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1; + memcpy(cfg->data, val.c_str(), val.length()); + strcpy(cfg->data + cfg->name_off, pack->payload); + reply->set_len(base_head_size + pk->payload_len); + *used = base_head_size + pack->payload_len; + } + + return reply; +} +dyn_mem_ptr async_scanner::handle_get_opt_all(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = nullptr; + LPPACK_BASE pk = nullptr; + + *used = base_head_size; + { + std::string val(""); + uint32_t err = cfg_mgr_->get_config(val); + + reply = dyn_mem::memory(base_head_size + val.length() + 1); + pk = (LPPACK_BASE)reply->ptr(); + BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err); + strcpy(pk->payload, val.c_str()); + pk->payload_len = val.length() + 1; + reply->set_len(base_head_size + val.length() + 1); + } + + return reply; +} +dyn_mem_ptr async_scanner::handle_set_opt(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = nullptr; + LPPACK_BASE pk = nullptr; + + if (*used < base_head_size + pack->payload_len) + *used = 0; + else + { + LPCFGVAL cfg = (LPCFGVAL)pack->payload, + cfg_ret = nullptr; + std::string name(cfg->data + cfg->name_off), val0(sane_cfg_provider::to_readable_string(cfg->data + cfg->val_off, (data_type)cfg->type)), val1(""); + size_t l = base_head_size + sizeof(CFGVAL) + name.length() + 1 + cfg->max_size + 1, val_size = cfg->val_size; + int32_t err = 0; + uint32_t after = 0; + + reply = dyn_mem::memory(l); + pk = (LPPACK_BASE)reply->ptr(); + cfg_ret = (LPCFGVAL)pk->payload; + cfg_ret->name_off = 0; + strcpy(cfg_ret->data + cfg_ret->name_off, name.c_str()); + cfg_ret->val_off = name.length() + 1; + memcpy(cfg_ret->data + cfg_ret->val_off, cfg->data + cfg->val_off, cfg->val_size); + cfg_ret->val_size = cfg->val_size; + cfg_ret->max_size = cfg->max_size; + cfg_ret->type = cfg->type; + err = cfg_mgr_->set_config(cfg->data + cfg->name_off, cfg_ret->data + cfg_ret->val_off, &val_size, &after); + cfg_ret->after_do = after; + cfg_ret->val_size = val_size; + BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err); + pk->payload_len = sizeof(CFGVAL) + name.length() + 1 + cfg->max_size + 1; + reply->set_len(l); + val1 = sane_cfg_provider::to_readable_string(cfg_ret->data + cfg_ret->val_off, (data_type)cfg->type); + if(val0 == val1) + log_cls::log(LOG_LEVEL_DEBUG, "Set '%s' value to '%s'\n", name.c_str(), val0.c_str()); + else + log_cls::log(LOG_LEVEL_DEBUG, "Set '%s' value to '%s', but applied '%s'\n", name.c_str(), val0.c_str(), val1.c_str()); + } + + return reply; +} +dyn_mem_ptr async_scanner::handle_file_receive(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = nullptr; + LPPACK_BASE pk = nullptr; + + if(*used < pack->payload_len + pack->size) + { + *used = 0; + } + else + { + LPTXFILE pfi = (LPTXFILE)pack->payload; + std::string path(pfi->path); + int err = 0; + file_saver *saver = new file_saver(); + + err = saver->open(path.c_str(), pfi->size); + reply = dyn_mem::memory(base_head_size); + reply->set_len(base_head_size); + BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); + *used = base_head_size + pack->payload_len; + if(err) + { + saver->release(); + saver = nullptr; + } + else + { + saver->set_packet_param(pack->cmd, pack->pack_id); + } + log_cls::log(LOG_LEVEL_DEBUG, "receive file (%u bytes): %s = %d\n", pfi->size, path.c_str(), err); + *required = dynamic_cast(saver); + } + + return reply; +} +dyn_mem_ptr async_scanner::handle_file_send(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = dyn_mem::memory(base_head_size); + LPPACK_BASE pk = (LPPACK_BASE)reply->ptr(); + + if(*used < pack->payload_len + pack->size) + { + *used = 0; + } + else + { + LPTXFILE pfi = (LPTXFILE)pack->payload; + std::string path(pfi->path); + int err = 0; + file_reader *reader = new file_reader(); + + err = reader->open(path.c_str()); + reply = dyn_mem::memory(base_head_size + sizeof(TXFILE)); + reply->set_len(base_head_size + sizeof(TXFILE)); + BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); + *used = base_head_size + pack->payload_len; + log_cls::log(LOG_LEVEL_DEBUG, "To send file '%s' with %u bytes = %d\n", path.c_str(), reader->get_rest(), err); + if(err) + { + reader->release(); + reader = nullptr; + } + else + { + ((LPPACK_BASE)reply->ptr())->payload_len = sizeof(TXFILE); + ((LPTXFILE)((LPPACK_BASE)reply->ptr())->payload)->size = reader->get_rest(); + reader->set_packet_param(pack->cmd, pack->pack_id); + } + *required = dynamic_cast(reader); + } + + return reply; +} +dyn_mem_ptr async_scanner::handle_scan_start(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + if(!used) + { + reply_start_ = true; + return nullptr; + } + +#ifdef TEMPORARY_API + if(reg_img_cb) + { + reg_img_cb = set_image_receiver(::push_image, this); + } +#endif + + uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = dyn_mem::memory(base_head_size); + + img_cnt_ = 0; + scan_id_ = pack->pack_id; + scan_err_ = 0; + reply_start_ = false; + + // { + // reg_image_callback(); + // ctrl_handler(-1, (usb_ctrlrequest*)SR_IM_CLEAR, (unsigned char*)0); + // log_cls::log(LOG_LEVEL_ALL, "Memory usage before starting to scan: %s\n", sys_util::format_readable_bytes(sys_util::get_memory_usage("scan")).c_str()); + // bool ret = ctrl_handler(-1, (usb_ctrlrequest*)15, (unsigned char*)0x160); // hardware configuration + // + // ctrl_handler(-1, (usb_ctrlrequest*)SR_SCAN_CNT, (unsigned char*)scan_cnt_); + // ctrl_handler(-1, (usb_ctrlrequest*)SR_SCAN_DPI, (unsigned char*)dpi_); + // ctrl_handler(-1, (usb_ctrlrequest*)SR_CONFIF_IMGPROCPARAM, (unsigned char*)0); + // log_cls::log(LOG_LEVEL_ALL, "Start scanning %d papers and %d DPI ...\n", scan_cnt_, dpi_); + // ret = ctrl_handler(-1, nullptr, nullptr); + // log_cls::log(LOG_LEVEL_ALL, "Start scanning %s\n", ret ? "OK" : "Failed"); + // log_cls::log(LOG_LEVEL_ALL, "Memory usage after scanning started: %s\n", sys_util::format_readable_bytes(sys_util::get_memory_usage("scan")).c_str()); + // } + + *used = base_head_size; + reply->set_len(base_head_size); + log_cls::log_memory_usage("before starting to scan"); + scan_err_ = capture_->start(); + log_cls::log_memory_usage("after scanning"); + BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, scan_err_); + *used |= INT32_MAX + 1; + + return reply; +} +dyn_mem_ptr async_scanner::handle_scan_stop(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = dyn_mem::memory(base_head_size); + + log_cls::log(LOG_LEVEL_ALL, "Received command Stop-Scan.\n"); + BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, capture_->stop()); + reply->set_len(base_head_size); + *used = base_head_size; + + return reply; +} +dyn_mem_ptr async_scanner::handle_process_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = dyn_mem::memory(base_head_size); + LPPACK_BASE pk = (LPPACK_BASE)reply->ptr(); + + *used = base_head_size + pack->payload_len; + BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, EINVAL); + reply->set_len(base_head_size); + + return reply; +} + + +uint32_t async_scanner::stop(void) +{ + if(usb_) + { + usb_->stop(); + } +} + +// void async_scanner::save_image(MemoryPtr data, bool img) +// { +// static uint64_t max_mem = 0; + +// if(img) +// { +// uint64_t n = sys_util::get_memory_usage("scan"); +// uint32_t que = 0; +// image_packet *ip = new image_packet(data, ++img_cnt_, scan_id_, n); + +// if(max_mem < n) +// max_mem = n; + +// que = usb_->write_bulk(ip); +// ip->release(); + +// // check has completed ? +// if(scan_over_pack_) +// { +// ctrl_handler(-2, (usb_ctrlrequest*)SR_GET_IMAGEPROCESSDONE, (unsigned char*)&n); +// if(n) +// { +// usb_->write_bulk(scan_over_pack_); +// scan_over_pack_->release(); +// scan_over_pack_ = nullptr; +// } +// } +// } +// else if(data) +// { +// HGIntInfo* info = (HGIntInfo*)data->data(); +// dyn_mem_ptr reply = dyn_mem::memory(sizeof(PACK_BASE)); +// int cmd = /*PACK_CMD_SCAN_FINISHED_ROGER*/0, +// err = 0; + +// if(info->From != HGType::MBEvent || scan_id_ == 0) +// log_cls::log(LOG_LEVEL_ALL, "Scanner event: From = %d, Code = %d, Img_Index = %d\n", info->From, info->Code, info->Img_Index); + +// if(info->From == HGType::MtBoard) +// { +// cmd = PACK_CMD_SCAN_FINISHED_ROGER; +// switch(info->Code) +// { +// case 2: +// err = SCANNER_STATUS_NO_PAPER; +// break; +// case 4: +// err = SCANNER_STATUS_COVER_OPENNED; +// break; +// case 8: +// err = SCANNER_STATUS_FEED_FAILED; +// break; +// case 0x10: +// err = SCANNER_STATUS_PAPER_JAMMED; +// break; +// case 0x20: +// err = SCANNER_STATUS_DOUBLE_FEEDED; +// break; +// case 0x40: +// err = SCANNER_STATUS_STAPLE_ON; +// break; +// case 0x80: +// err = SCANNER_STATUS_PAPER_ASKEW; +// break; +// case 0x20000: +// break; +// } +// } +// else if(info->From == HGType::IMG) +// { +// if(info->Code == 1) +// { +// err = SCANNER_STATUS_DOGEAR; +// cmd = PACK_CMD_SCAN_FINISHED_ROGER; +// } +// else if(info->Code == 2) +// { +// err = SCANNER_STATUS_SIZE_ERR; +// cmd = PACK_CMD_SCAN_FINISHED_ROGER; +// } +// } +// else if(info->From == HGType::V4L2 || info->From == HGType::STOPSCAN) +// { +// cmd = PACK_CMD_SCAN_FINISHED_ROGER; +// } + +// if(scan_id_ == 0 && info->From == HGType::MBEvent) +// { +// BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), PACK_CMD_STATUS_ROGER, 0, info->Code); +// reply->set_len(sizeof(PACK_BASE)); +// usb_->write_bulk(reply); +// } +// else +// { +// if(err && scan_err_ == 0) +// scan_err_ = err; +// if(scan_id_ && /*cmd == PACK_CMD_SCAN_FINISHED_ROGER*/info->From == HGType::STOPSCAN && scan_over_pack_ == nullptr) +// { +// char ebuf[20] = {0}; + +// err = scan_err_; +// log_cls::log(LOG_LEVEL_ALL, "Scan over with error: %s; Max memory usage: %s\n", log_cls::str_scanner_status((scanner_status)scan_err_, ebuf), sys_util::format_readable_bytes(max_mem).c_str()); +// max_mem = 0; +// BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), cmd, scan_id_, err); +// reply->set_len(sizeof(PACK_BASE)); +// scan_id_ = 0; + +// // check if the image-proc-queue has completed ... +// // ctrl_handler(-2, (usb_ctrlrequest*)SR_GET_IMAGEPROCESSDONE, (unsigned char*)&err); +// err = 1; +// if(err) +// usb_->write_bulk(reply); +// else +// { +// scan_over_pack_ = reply; +// scan_over_pack_->add_ref(); +// } +// } +// } +// reply->release(); +// } +// else +// { +// // paper count ... +// dyn_mem_ptr reply = dyn_mem::memory(sizeof(PACK_BASE)); +// BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), PACK_CMD_SCAN_PAPER_ROGER, 0, 0); +// reply->set_len(sizeof(PACK_BASE)); +// usb_->write_bulk(reply); +// reply->release(); +// } +// } + +// int32_t async_scanner::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) +// { +// int32_t ret = EINVAL; + +// if(!len) +// return ret; + +// if(cfg_name) +// { +// gb_json *jsn = new gb_json(); +// if(jsn->attach_text(&cfg_text_[0])) +// { +// ret = inner_get_config(jsn, buf, len, cfg_name, strval); +// // gb_json* child = nullptr; + +// // ret = ENOENT; +// // if(jsn->get_value(cfg_name, child) && child) +// // { +// // std::string val(sane_cfg_provider::sane_option_value_get(child, "cur", strval)); +// // child->release(); + +// // if(*len < val.length()) +// // { +// // *len = val.length(); +// // ret = ENOMEM; +// // } +// // else +// // { +// // memcpy(buf, val.c_str(), val.length()); +// // *len = val.length(); +// // } +// // } +// jsn->release(); +// } +// } +// else +// { +// if(*len < cfg_text_.length() + 1) +// { +// *len = cfg_text_.length() + 4; +// ret = ENOMEM; +// } +// else +// { +// strcpy((char*)buf, cfg_text_.c_str()); +// *len = cfg_text_.length(); +// ret = 0; +// } +// } + +// return ret; +// } +// int32_t async_scanner::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +// { +// gb_json *jsn = new gb_json(); +// int32_t ret = EINVAL; + +// if(jsn->attach_text(&cfg_text_[0])) +// { +// gb_json* child = nullptr; + +// ret = ENOENT; +// if(jsn->get_value(cfg_name, child) && child) +// { +// int val = 0; +// child->get_value("affect", val); +// if(afterdo) +// *afterdo = val; + +// if(strcmp(cfg_name, "resolution") == 0) +// { +// child->get_value("cur", val); +// ret = EUCLEAN; +// val = *(int*)data; +// if(val == 100 || val == 150 || val == 200 || val == 300 || val == 600) +// ret = 0; +// else if(val < 125) +// val = 100; +// else if(val < 175) +// val = 150; +// else if(val < 250) +// val = 200; +// else if(val < 450) +// val = 300; +// else +// val = 600; +// *(int*)data = val; +// child->set_value("cur", val); +// dpi_ = val; +// log_cls::log(LOG_LEVEL_ALL, "Set %s to %d\n", cfg_name, dpi_); +// cfg_text_ = jsn->to_string(); +// } +// else if(strcmp(cfg_name, "count") == 0) +// { +// child->get_value("cur", val); +// ret = EUCLEAN; +// val = *(int*)data; +// if(val == -1 || val == 1) +// ret = 0; +// else +// val = -1; +// *(int*)data = val; +// child->set_value("cur", val); +// scan_cnt_ = val; +// log_cls::log(LOG_LEVEL_ALL, "Set %s to %d\n", cfg_name, scan_cnt_); +// cfg_text_ = jsn->to_string(); +// } +// child->release(); +// } +// jsn->release(); +// } + +// return ret; +// } +// void async_scanner::update_enabled(std::function get_opt) +// { +// gb_json *jsn = new gb_json(); +// int32_t ret = EINVAL; + +// if(jsn->attach_text(&cfg_text_[0])) +// { +// sane_cfg_provider::update_option_enable_status(jsn, get_opt); +// cfg_text_ = std::move(jsn->to_string()); +// } + +// jsn->release(); +// } +// int32_t async_scanner::get_value(const char* name, const char* key, std::string& val) +// { +// gb_json* root = new gb_json(), *child = nullptr; +// int32_t ret = ENOENT; + +// if(root->attach_text(&cfg_text_[0])) +// { +// if(root->get_value(name, child) && child) +// { +// if(sane_cfg_provider::raw_value_in_json(child, key, val)) +// ret = 0; +// child->release(); +// } +// } +// root->release(); + +// return ret; +// } + diff --git a/device/gxx-linux/usb/src/async_model/scanner/async_scanner.h b/device/gxx-linux/usb/src/async_model/scanner/async_scanner.h new file mode 100644 index 0000000..b11bd41 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/scanner/async_scanner.h @@ -0,0 +1,65 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "camtp.h" +#include "buildconf.h" +#include "usb_gadget.h" +#include "io/data.h" + +#include "common/referer.h" + +class async_usb_gadget; +class sane_cfg_mgr; +class image_capture; +class img_processor; +class gb_json; + +class async_scanner : public refer +{ + async_usb_gadget *usb_; + sane_cfg_mgr *cfg_mgr_; + image_capture *capture_; + img_processor *img_prc_; + + MUTEX locker_; + uint32_t img_cnt_; + uint32_t scan_id_; + uint32_t scan_err_; + volatile bool reply_start_; + + dyn_mem_ptr unhandled_ep0(struct usb_functionfs_event* pev); + dyn_mem_ptr handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + void init(void); + + dyn_mem_ptr handle_simple_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + dyn_mem_ptr handle_get_opt_value(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + dyn_mem_ptr handle_get_opt_all(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + dyn_mem_ptr handle_set_opt(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + dyn_mem_ptr handle_file_receive(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + dyn_mem_ptr handle_file_send(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + dyn_mem_ptr handle_scan_start(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + dyn_mem_ptr handle_scan_stop(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + dyn_mem_ptr handle_process_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + +public: + async_scanner(usb_gadget* gadget); + +protected: + ~async_scanner(); + +public: + // void save_image(MemoryPtr data, bool img); + + // virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; + // virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + // virtual void update_enabled(std::function get_opt) override; + // virtual int32_t get_value(const char* name, const char* key, std::string& val) override; + void push_image(int data_type, void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel clr, img_status status, bool img_new, bool img_over); + +public: + uint32_t stop(void); +}; diff --git a/device/gxx-linux/usb/src/async_model/scanner/readonly_opts.cpp b/device/gxx-linux/usb/src/async_model/scanner/readonly_opts.cpp new file mode 100644 index 0000000..b95ebca --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/scanner/readonly_opts.cpp @@ -0,0 +1,115 @@ +#include "readonly_opts.h" + +#include "common/json/gb_json.h" +#include "common/sys_util.h" + +#include + +static std::string readonly_json = + "{\"dev-sn\":{\"category\":\"base\",\"readonly\":true,\"affect\":0,\"group\":\"\\u8BBE\\u5907\\u5C5E\\u6027\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8bbe\\u5907\\u5e8f\\u5217\\u53f7\",\"desc\":\"\\u8bbe\\u5907\\u552f\\u4e00\\u7f16\\u7801\",\"type\":\"string\",\"cur\":\"G100S20230001\",\"size\":20,\"ver\":1},\"fmw-ver\":{\"category\":\"base\",\"readonly\":true,\"affect\":0,\"group\":\"\\u8BBE\\u5907\\u5C5E\\u6027\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u56fa\\u4ef6\\u7248\\u672c\\u53f7\",\"desc\":\"\\u8bbe\\u5907\\u9a71\\u52a8\\u7248\\u672c\\u53f7\",\"type\":\"string\",\"cur\":\"FMWV1001\",\"size\":10,\"ver\":1},\"ip-addr\":{\"category\":\"base\",\"readonly\":true,\"affect\":0,\"group\":\"\\u8BBE\\u5907\\u5C5E\\u6027\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8bbe\\u5907IP\\u5730\\u5740\",\"desc\":\"\\u5f53\\u8bbe\\u5907\\u8fde\\u63a5\\u7f51\\u7edc\\u65f6\\u5206\\u914d\\u7684IP\\u5730\\u5740\",\"type\":\"string\",\"cur\":\"0.0.0.0\",\"size\":60,\"ver\":1},\"mac-addr\":{\"category\":\"base\",\"readonly\":true,\"affect\":0,\"group\":\"\\u8BBE\\u5907\\u5C5E\\u6027\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8bbe\\u5907MAC\\u5730\\u5740\",\"desc\":\"\\u8bbe\\u5907MAC\\u5730\\u5740\",\"type\":\"string\",\"cur\":\"00:11:22:33:44:55\",\"size\":30,\"ver\":1}}"; + +// C2-B0-AF-79-75-D6 +// + +readonly_cfg::readonly_cfg() : jsn_(nullptr) +{ + jsn_ = new gb_json(); + jsn_->attach_text(&readonly_json[0]); +} +readonly_cfg::~readonly_cfg() +{ + jsn_->release(); +} + +int32_t readonly_cfg::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) +{ + if (!len) + return EINVAL; + + std::string val(""), str(""); + + if (cfg_name) + { + if (strcmp(cfg_name, "ip-addr") == 0) + str = val = sys_util::get_ip(); + else if (strcmp(cfg_name, "mac-addr") == 0) + str = val = sys_util::get_mac(); + else + { + gb_json* child = nullptr; + if (jsn_->get_value(cfg_name, child) && child) + { + val = sane_cfg_provider::sane_option_value_get(child, "cur", &str); + + child->release(); + } + } + } + else + { + std::string cur(sys_util::get_ip()); + if (!cur.empty()) + { + gb_json* child = nullptr; + if (jsn_->get_value("ip-addr", child) && child) + { + child->set_value("cur", cur.c_str()); + child->release(); + } + } + + cur = sys_util::get_mac(); + if (!cur.empty()) + { + gb_json* child = nullptr; + if (jsn_->get_value("mac-addr", child) && child) + { + child->set_value("cur", cur.c_str()); + child->release(); + } + } + + val = jsn_->to_string(); + } + + if (val.empty()) + return ENOENT; + + if(strval) + *strval = std::move(str); + + if (*len < val.length()) + { + *len = val.length() + 4; + return ENOMEM; + } + else + { + memcpy(buf, val.c_str(), val.length()); + *len = val.length(); + + return 0; + } +} +int32_t readonly_cfg::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +{ + // read-only attributes not support this operation !!! + return EINVAL; +} +void readonly_cfg::update_enabled(std::function get_opt) +{} +int32_t readonly_cfg::get_value(const char* name, const char* key, std::string& val) +{ + int32_t ret = ENOENT; + gb_json* child = nullptr; + + if(jsn_->get_value(name, child) && child) + { + if(sane_cfg_provider::raw_value_in_json(child, key, val)) + ret = 0; + + child->release(); + } + + return ret; +} diff --git a/device/gxx-linux/usb/src/async_model/scanner/readonly_opts.h b/device/gxx-linux/usb/src/async_model/scanner/readonly_opts.h new file mode 100644 index 0000000..a32a5c6 --- /dev/null +++ b/device/gxx-linux/usb/src/async_model/scanner/readonly_opts.h @@ -0,0 +1,31 @@ +// readonly options +// +// 2023-04-26 + +#pragma once + +#include "common/sane_cfg.h" + +class gb_json; + +// C2-B0-AF-79-75-D6 + +class readonly_cfg : public sane_cfg_provider +{ + gb_json* jsn_; + + std::string get_ip(void); + std::string get_mac(void); + +public: + readonly_cfg(); + +protected: + ~readonly_cfg(); + +public: + virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) override; + virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; + virtual void update_enabled(std::function get_opt) override; + virtual int32_t get_value(const char* name, const char* key, std::string& val) override; +}; diff --git a/device/gxx-linux/usb/src/common/CMakeLists.txt b/device/gxx-linux/usb/src/common/CMakeLists.txt deleted file mode 100644 index 466b700..0000000 --- a/device/gxx-linux/usb/src/common/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -project(common) -add_compile_options(-std=c++11) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") -aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS) -file(GLOB DIR_HEADS "${PROJECT_SOURCE_DIR}/*" "${PROJECT_SOURCE_DIR}/json/*") -set(DIR_SRCS ${DIR_SRCS} ${DIR_HEADS}) -add_library(${PROJECT_NAME} STATIC ${DIR_SRCS}) - -target_link_libraries(${PROJECT_NAME} PRIVATE - dl - pthread - rt - ) -target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR} - ) -set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../scanner/build/) diff --git a/device/gxx-linux/usb/src/common/cmd.cpp b/device/gxx-linux/usb/src/common/cmd.cpp deleted file mode 100644 index d8abf93..0000000 --- a/device/gxx-linux/usb/src/common/cmd.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "cmd.h" - - - - -namespace parser -{ - static void command_line_to_arguments(const char* cmdl, std::vector& args) - { - while(*cmdl) - { - const char* h = cmdl; - while(*h == ' ' || *h == '\t') - h++; - if(*h == 0) - break; - - cmdl = h; - if(*h == '\"') - { - cmdl++; - h++; - while(*h) - { - if(*h == '\"') - break; - if(*h == '\\') - h++; - h++; - } - } - else - { - while(*h) - { - if(*h == ' ' || *h == '\t') - break; - h++; - } - } - if(h > cmdl) - args.push_back(std::string(cmdl, h - cmdl)); - else if(*h == '\"') - args.push_back(""); - - if(*h == 0) - break; - - cmdl = h + 1; - } - } -} - - - - -cmd_line::cmd_line() -{} -cmd_line::~cmd_line() -{} - -cmd_line* cmd_line::from_console(const char* tips) -{ - std::string in(""); - char ch = 0; - - if(!tips || *tips == 0) - tips = "input"; - - printf("%s%s>%s", CONSOLE_COLOR_FRONT_BLUE, tips, CONSOLE_COLOR_NONE); - while((ch = getchar()) != '\n') - in.append(1, ch); - - return cmd_line::from_command_line(in.c_str()); -} -cmd_line* cmd_line::from_command_line(const char* cmdl) -{ - cmd_line* cmd = new cmd_line(); - - cmd->cmd_line_ = cmdl; - parser::command_line_to_arguments(cmdl, cmd->arguments_); - - return cmd; -} - -size_t cmd_line::count(void) -{ - return arguments_.size(); -} -const char* cmd_line::parameter(int ind) -{ - if(ind >= 0 && ind < arguments_.size()) - return arguments_[ind].c_str(); - else - return nullptr; -} -const char* cmd_line::parameter(const char* key) -{ - for(int i = 0; i < arguments_.size() - 1; ++i) - { - if(arguments_[i] == key) - return arguments_[i + 1].c_str(); - } - - return nullptr; -} diff --git a/device/gxx-linux/usb/src/common/cmd.h b/device/gxx-linux/usb/src/common/cmd.h deleted file mode 100644 index 91a65c3..0000000 --- a/device/gxx-linux/usb/src/common/cmd.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -// command line utility -// -// created on 2023-02-10 -// - -#include "referer.h" -#include -#include - -#define CONSOLE_COLOR_NONE "\033[0m" -#define CONSOLE_COLOR_FRONT_BLACK "\033[0;30m" -#define CONSOLE_COLOR_FRONT_DARK_GRAY "\033[1;30m" -#define CONSOLE_COLOR_FRONT_RED "\033[0;31m" -#define CONSOLE_COLOR_FRONT_LIGHT_RED "\033[1;31m" -#define CONSOLE_COLOR_FRONT_GREEN "\033[0;32m" -#define CONSOLE_COLOR_FRONT_LIGHT_GREEN "\033[1;32m" -#define CONSOLE_COLOR_FRONT_BROWN "\033[0;33m" -#define CONSOLE_COLOR_FRONT_YELLOW "\033[1;33m" -#define CONSOLE_COLOR_FRONT_BLUE "\033[0;34m" -#define CONSOLE_COLOR_FRONT_LIGHT_BLUE "\033[1;34m" -#define CONSOLE_COLOR_FRONT_PURPLE "\033[0;35m" -#define CONSOLE_COLOR_FRONT_LIGHT_PURPLE "\033[1;35m" -#define CONSOLE_COLOR_FRONT_CYAN "\033[0;36m" -#define CONSOLE_COLOR_FRONT_LIGHT_CYAN "\033[1;36m" -#define CONSOLE_COLOR_FRONT_LIGHT_GRAY "\033[0;37m" -#define CONSOLE_COLOR_FRONT_WHITE "\033[1;37m" - -#define CONSOLE_COLOR_BACK_BLACK "\033[0;40m" -#define CONSOLE_COLOR_BACK_DARK_GRAY "\033[1;40m" -#define CONSOLE_COLOR_BACK_RED "\033[0;41m" -#define CONSOLE_COLOR_BACK_LIGHT_RED "\033[1;41m" -#define CONSOLE_COLOR_BACK_GREEN "\033[0;42m" -#define CONSOLE_COLOR_BACK_LIGHT_GREEN "\033[1;42m" -#define CONSOLE_COLOR_BACK_BROWN "\033[0;43m" -#define CONSOLE_COLOR_BACK_YELLOW "\033[1;43m" -#define CONSOLE_COLOR_BACK_BLUE "\033[0;44m" -#define CONSOLE_COLOR_BACK_LIGHT_BLUE "\033[1;44m" -#define CONSOLE_COLOR_BACK_PURPLE "\033[0;45m" -#define CONSOLE_COLOR_BACK_LIGHT_PURPLE "\033[1;45m" -#define CONSOLE_COLOR_BACK_CYAN "\033[0;46m" -#define CONSOLE_COLOR_BACK_LIGHT_CYAN "\033[1;46m" -#define CONSOLE_COLOR_BACK_LIGHT_GRAY "\033[0;47m" -#define CONSOLE_COLOR_BACK_WHITE "\033[1;47m" - - -namespace console -{ - // special effects: - // \033[0m close all attributes - // \033[1m set high-light - // \033[4m underline - // \033[5m blink - // \033[7m reverse(反显) - // \033[8m blanking(消隐) - // \033[30m -- \033[37m set foreground color - // \033[40m -- \033[47m set background color - // - // cursor position: - // \033[nA move up n lines - // \033[nB move down n lines - // \033[nC move right n cols - // \033[nD move left n cols - // \033[y;xH set cursor position - // \033[2J clear screen - // \033[K clear the line after cursor position - // \033[s save cursor position - // \033[u restore cursor position - // \033[?25l hide cursor - // \033[?25h show cursor -}; - -class cmd_line : public refer -{ - std::string cmd_line_; - std::vector arguments_; - -protected: - cmd_line(); - ~cmd_line(); - -public: - static cmd_line* from_console(const char* tips); - static cmd_line* from_command_line(const char* cmdl); - -public: - size_t count(void); - const char* parameter(int ind); - const char* parameter(const char* key); -}; - diff --git a/device/gxx-linux/usb/src/common/event_monitor.cpp b/device/gxx-linux/usb/src/common/event_monitor.cpp deleted file mode 100644 index 657f3b1..0000000 --- a/device/gxx-linux/usb/src/common/event_monitor.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include "event_monitor.h" - -// #define __USE_GNU // for gettid of including file 'bits/unistd_ext.h' - -#include /* nonblocking */ -#include /*setrlimit */ -#include -#include -#include -#include -#include -#include -// #include // for gettid -#include -#include -#include - -#include "log_util.h" - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// event_handler -event_handler::event_handler() -{} -event_handler::~event_handler() -{} - - - - - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// parent_holder -parent_holder::parent_holder() -{} -parent_holder::~parent_holder() -{} - - - - - - - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// linux - epoll wrapper ... -class epoll_wrapper : public event_monitor -{ - int32_t epoll_fd_; - int32_t quit_fd_[2]; - volatile bool run_; - std::vector threads_; - - static int32_t epoll_max; - - void clear_threads(void) - { - if(threads_.size()) - { - for (size_t i = 0; i < threads_.size(); ++i) - { - if (threads_[i]->joinable()) - threads_[i]->join(); - threads_[i].reset(); - } - threads_.clear(); - } - } - void close_monitor_fd(void) - { - if (epoll_fd_ != -1) - close(epoll_fd_); - epoll_fd_ = -1; - } - void clear(void) - { - clear_threads(); - close_monitor_fd(); - } - void monitor_thread(void) - { - log_cls::log(LOG_LEVEL_DEBUG, "monitor thread(%p) of object(%p) is working ...\n", gettid(), this); - while (run_) - { - struct epoll_event evs; - - memset(&evs, 0, sizeof(evs)); - if (epoll_wait(epoll_fd_, &evs, 1, -1) == -1) - continue; - if (evs.events == EPOLLOUT && evs.data.fd == quit_fd_[1]) - break; - - if (evs.events == EPOLLIN) - ((event_handler*)evs.data.ptr)->on_event(event_handler::EVENT_READ, nullptr, 0); - else if (evs.events == EPOLLOUT) - ((event_handler*)evs.data.ptr)->on_event(event_handler::EVENT_WRITE, nullptr, 0); - else - ; - } - log_cls::log(LOG_LEVEL_DEBUG, "monitor thread(%p) of object(%p) finished working.\n", gettid(), this); - } - -protected: - virtual ~epoll_wrapper() - { - stop(); - } - -public: - epoll_wrapper(const char* desc) : event_monitor(desc), epoll_fd_(-1), run_(true) - { - memset(quit_fd_, -1, sizeof(quit_fd_)); - } - -public: - virtual int32_t start(int32_t threads = 1) override - { - int32_t ret = stop(); - struct rlimit rt; - - rt.rlim_max = rt.rlim_cur = epoll_wrapper::epoll_max; - if (ret == 0 && setrlimit(RLIMIT_NOFILE, &rt) == 0) - { - epoll_fd_ = epoll_create(epoll_wrapper::epoll_max); - if (epoll_fd_ == -1) - { - ret = errno; - log_cls::log(LOG_LEVEL_FATAL, "epoll_create for '%s' failed: %s\n", desc_.c_str(), strerror(ret)); - } - else - { - run_ = true; - for (size_t i = 0; i < (size_t)threads; ++i) - { - THREAD_PTR t;//(new std::thread(&epoll_wrapper::monitor_thread, this)); - t.reset(new std::thread(&epoll_wrapper::monitor_thread, this)); - threads_.push_back(t); - } - } - } - else - { - log_cls::log(LOG_LEVEL_FATAL, "setrlimit for '%s-epoll' failed: %s\n", desc_.c_str(), strerror(ret)); - } - - return ret; - } - virtual int32_t stop(void) override - { - if(threads_.size()) - { - struct epoll_event ev; - #ifdef __USE_GNU - pipe2(quit_fd_, O_NONBLOCK); - #else - pipe(quit_fd_); - #endif - - log_cls::log(LOG_LEVEL_DEBUG, "quit fd[0] = %p, fd[1] = %p\n", quit_fd_[0], quit_fd_[1]); - - run_ = false; - ev.data.fd = quit_fd_[1]; - ev.events = EPOLLOUT | EPOLLET | EPOLLONESHOT; - for(size_t i = 0; i < threads_.size(); ++i) - epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, ev.data.fd, &ev); - clear_threads(); - close(quit_fd_[0]); - close(quit_fd_[1]); - memset(quit_fd_, -1, sizeof(quit_fd_)); - } - - close_monitor_fd(); - - return 0; - } - - virtual int32_t add_fd(event_handler* handler) override - { - struct epoll_event ev; - int32_t ret = -1; - - if (!handler || handler->get_fd() == -1) - return EINVAL; - - if (epoll_fd_ == -1) - return EFAULT; - - handler->add_ref(); // add ref for epoll_event holder ... - ev.data.ptr = handler; - ev.events = EPOLLIN | EPOLLOUT | EPOLLET; // EPOLLONESHOT | EPOLLHUP - ret = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, handler->get_fd(), &ev); - if (ret == -1) - { - ret = errno; - log_cls::log(LOG_LEVEL_FATAL, "add fd(%d) to %s-epoll failed: %s\n", handler->get_fd(), desc_.c_str(), strerror(ret)); - handler->release(); - } - - return ret; - } - virtual int32_t remove_fd(event_handler* handler) override - { - struct epoll_event ev; - int32_t ret = -1; - - if (!handler || handler->get_fd() == -1) - return EINVAL; - - if (epoll_fd_ == -1) - return EFAULT; - - ev.data.ptr = handler; - ev.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLHUP; // EPOLLONESHOT - ret = epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, handler->get_fd(), &ev); - - if (ret == 0) - { - // ENOENT returned if object 'handler' has not registered, so we can free it here when success in EPOLL_CTL_DEL ... - handler->release(); - } - else - { - ret = errno; - log_cls::log(LOG_LEVEL_FATAL, "remove fd(%d) from %s-epoll failed: %s\n", handler->get_fd(), desc_.c_str(), strerror(ret)); - } - - return ret; - } -}; -int32_t epoll_wrapper::epoll_max = 100; - - - - - - - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// event_handler -event_monitor::event_monitor(const char* desc) : desc_(desc ? desc : "") -{ - log_cls::log(LOG_LEVEL_DEBUG, "+event_monitor(%p) of '%s' contructing ...\n", this, desc_.c_str()); -} -event_monitor::~event_monitor() -{ - log_cls::log(LOG_LEVEL_DEBUG, "-event_monitor(%p) of '%s' destroyed\n", this, desc_.c_str()); -} - -event_monitor* event_monitor::create(const char* desc, int32_t type) -{ - if (type == EV_TYPE_EPOLL) - return dynamic_cast(new epoll_wrapper(desc)); - else - return nullptr; -} diff --git a/device/gxx-linux/usb/src/common/event_monitor.h b/device/gxx-linux/usb/src/common/event_monitor.h deleted file mode 100644 index 2a77a29..0000000 --- a/device/gxx-linux/usb/src/common/event_monitor.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once - -// event monitor -// -// created on 2022-11-29 -// - -#include "referer.h" -#include "packet.h" - -#include -#include - -typedef std::shared_ptr THREAD_PTR; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// event definition ... -enum scanner_event -{ - SCANNER_EVENT_NONE = 0, - - // 1 - IPC - SCANNER_EVENT_IPC_DATA_RECEIVED = 1, - SCANNER_EVENT_IPC_DATA_SENT, - - // 2 - image-collector - SCANNER_EVENT_COLLECTOR_WORKING = 100, // on_event(, nullptr, 0), the first message after start success - - // normal image, double feeding image, jammed image, stapled imge, size-check error image ... - SCANNER_EVENT_COLLECTOR_IMG_DATA, // on_event(, (LPIMGD)data, bytes of data), image data transfer, buffer can be re-used when return - - SCANNER_EVENT_COLLECTOR_PAPER_ON, // on_event(, (bool*)paper_on, (bool)local_display) - SCANNER_EVENT_COLLECTOR_COVER_OPENNED, // on_event(, (bool*)openned, (bool)local_display) - SCANNER_EVENT_COLLECTOR_SLEEPPING, // on_event(, (bool*)sleepping, (bool)local_display) - SCANNER_EVENT_COLLECTOR_ERROR, // on_event(, (char*)err-msg, (bool)local_display), used when unknown fatal error occurs! - - SCANNER_EVENT_COLLECTOR_STOPPED, // on_event(, (char*)err-msg, (size_t)err-code), the last message after start success - - // 3 - image-process - SCANNER_EVENT_IMAGE_PROC_FINAL_BUF = 200, // on_event(, (void**)buf, (size_t)len), get buffer for store the final image - SCANNER_EVENT_IMAGE_PROC_OK, // on_event(, ) - SCANNER_EVENT_IMAGE_PROC_ERR, - - // 4 - resource - SCANNER_EVENT_RESOURCE_LOW_MEM = 300, // on_event(, (bool*)low_mem, (bool)local_display) - SCANNER_EVENT_RESOURCE_LOW_DISK, // on_event(, (bool*)low_disk, (bool)local_display) - SCANNER_EVENT_RESOURCE_HIGH_CPU, // on_event(, (bool*)high_cpu, (bool)local_display) -}; - -typedef struct _img_data -{ - LPPACKIMAGE info; - uint8_t* data; -}IMGD, *LPIMGD; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// object event_handler -// -// derived from 'event_handler' if your class will handle some events of drived by events -// -class event_handler : public refer -{ -protected: - event_handler(); - virtual ~event_handler(); - -public: - virtual int32_t on_event(int32_t ev, void* data, size_t data_len) = 0; - virtual int32_t get_fd(void) = 0; - - enum - { - EVENT_READ = 0, - EVENT_WRITE, - }; -}; - -class parent_holder : public refer -{ -protected: - parent_holder(); - virtual ~parent_holder(); - -public: - virtual int32_t stop(void) = 0; // stop work and release parent ptr -}; - -// event_monitor to manage an event-driven model, this will trigger EVENT_READ/EVENT_WRITE events to 'handler' -// -class event_monitor : public refer -{ -protected: - std::string desc_; - -protected: - event_monitor(const char* desc); - virtual ~event_monitor(); - -public: - virtual int32_t start(int32_t threads = 1) = 0; - virtual int32_t stop(void) = 0; - - virtual int32_t add_fd(event_handler* handler) = 0; - virtual int32_t remove_fd(event_handler* handler) = 0; - - enum - { - EV_TYPE_POLL = 1, - EV_TYPE_EPOLL, - }; - static event_monitor* create(const char* desc, int32_t type = EV_TYPE_EPOLL); -}; - -class sane_cfg_provider : public refer -{ -public: - sane_cfg_provider() - {} - virtual ~sane_cfg_provider() - {} - -public: - // Function: get all or given name configuration value - // - // Parameters: buf - to receive the configuration value or all configuration JSON - // - // len - [in] bytes of 'buf', [out] - content bytes in 'buf', or minimum size needed - // - // cfg_name - given configuration name, if set, put current value of the configuration in 'buf', - // or put all configurations JSON text in 'buf' if was nullptr. refer to SANE-config - // - // Return: 0 - on success - // EINVAL - if paramter 'len' was nullptr - // ENOMEM - if size of 'buf' was too small, the minimum size needed is stored in 'len' - // ENOENT - the configuration named 'cfg_name' has not found - virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr) = 0; - - // Function: set value of configuration named 'cfg_name' - // - // Parameters: cfg_name - the configuration name - // - // data - the value address, nullptr is for restore to default value - // (bool*), (int*), (double*), (char*) - // - // len - bytes in 'data' - // - // Return: 0 - on success - // EINVAL - parameter was invalid. 'cfg_name' was nullptr - // ENOENT - configuration 'cfg_name' was not found - // EUCLEAN - content in 'data' was not exact, the exact value is stored in 'data', and bytes in 'len' - virtual int32_t set_config(const char* cfg_name, void* data, size_t* len) = 0; -}; - diff --git a/device/gxx-linux/usb/src/common/ipc_wrapper.cpp b/device/gxx-linux/usb/src/common/ipc_wrapper.cpp deleted file mode 100644 index 5c9fdac..0000000 --- a/device/gxx-linux/usb/src/common/ipc_wrapper.cpp +++ /dev/null @@ -1,373 +0,0 @@ -#include "ipc_wrapper.h" - -#include -#include - -#include "log_util.h" -#include "ipc_util.h" -#include "sys_util.h" - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// ipc_wrapper_shm -class ipc_wrapper_shm : public ipc_wrapper -{ - enum data_ind - { - DATA_INTER_CMD = 0, - }; - enum internal_cmd - { - INTER_CMD_NONE = 0, - INTER_CMD_EXIT, - }; - typedef struct _shm_pack - { - size_t space; // buffer length - size_t bytes; // data length - char data[4]; - }SHMPACK, *LPSHMPACK; - typedef struct _sync_shm // 1-lock(write_lock) --> 2-write content --> 3-notify read --> 4-wait(wait_sent) --> 5-return step 2 if data has not sent finished, or else to 6 --> 6-release(write_lock) --> 7-over - { - sem_t wait_arrive; // read event - sem_t wait_sent; // peer has read, i can re-write now - sem_t notify_read; // notify peer to read - sem_t notify_write; // notify peer to write - char data[8]; // internal data - }SYNCSHM, *LPSYNCSHM; - volatile bool run_; - MUTEX write_lock_; - int32_t id_; - shared_mem* shm_; - LPSYNCSHM sync_shm_; - linux_event* wait_arrive_; - linux_event* wait_sent_; - linux_event* notify_write_; - linux_event* notify_read_; - THREAD_PTR thread_; - LPSHMPACK buf_in_; - LPSHMPACK buf_out_; - bool buf_out_used_; - volatile bool cancel_write_; - - void create(const char* file, int32_t id, size_t bytes, unsigned sent_percent) - { - int32_t err = 0; - - shm_ = new shared_mem(); - err = shm_->open(id, &bytes, file); - if (err) - { - log_cls::log(LOG_LEVEL_FATAL, "ipc_wrapper_shm(%p) open shared memory(%s, %d, %s) failed: %s\n" - , this, file, id, sys_util::format_readable_bytes(bytes).c_str(), strerror(err)); - shm_->release(); - shm_ = nullptr; - - return; - } - - SHMPACK pack = { 0 }; - std::string desc("ipc_wrapper_shm-"); - char buf[80] = { 0 }, *ptr = shm_->get_mem(&pack.space); - int32_t pack_head = ALIGN_INT(sizeof(pack), 16), head = ALIGN_INT(sizeof(SYNCSHM), 16); - - sprintf(buf, "%d-", id); - desc += buf; - - sync_shm_ = (LPSYNCSHM)ptr; - ptr += head; - pack.space -= head + pack_head * 2; - head = ALIGN_INT(pack.space * sent_percent / 100, 16); - if (shm_->is_first()) - { - SYNCSHM ss; - - memcpy(sync_shm_, &ss, sizeof(ss)); - buf_in_ = (LPSHMPACK)ptr; - buf_in_->space = pack.space - head; - ptr += buf_in_->space + pack_head; - buf_out_ = (LPSHMPACK)ptr; - buf_out_->space = head; - //* - wait_arrive_ = new linux_event(&sync_shm_->wait_arrive, true, (desc + "wait_arrive").c_str()); - wait_sent_ = new linux_event(&sync_shm_->wait_sent, true, (desc + "wait_sent").c_str()); - notify_read_ = new linux_event(&sync_shm_->notify_read, true, (desc + "notify_read").c_str()); - notify_write_ = new linux_event(&sync_shm_->notify_write, true, (desc + "notify_write").c_str()); - /*/ - wait_arrive_ = new linux_event((desc + "wait_arrive").c_str(), ""); - wait_sent_ = new linux_event((desc + "wait_sent").c_str(), ""); - notify_write_ = new linux_event((desc + "notify_write").c_str(), ""); - notify_read_ = new linux_event((desc + "notify_read").c_str(), ""); - ///*//////////// - memset(sync_shm_->data, 0, sizeof(sync_shm_->data)); - } - else - { - //* - wait_sent_ = new linux_event(&sync_shm_->notify_write, false, (desc + "wait_sent").c_str()); - wait_arrive_ = new linux_event(&sync_shm_->notify_read, false, (desc + "wait_arrive").c_str()); - notify_write_ = new linux_event(&sync_shm_->wait_sent, false, (desc + "notify_write").c_str()); - notify_read_ = new linux_event(&sync_shm_->wait_arrive, false, (desc + "notify_read").c_str()); - /*/ - wait_arrive_ = new linux_event((desc + "notify_read").c_str(), ""); - wait_sent_ = new linux_event((desc + "notify_write").c_str(), ""); - notify_read_ = new linux_event((desc + "wait_arrive").c_str(), ""); - notify_write_ = new linux_event((desc + "wait_sent").c_str(), ""); - ///*//////////// - buf_out_ = (LPSHMPACK)ptr; - buf_in_ = (LPSHMPACK)(ptr + pack_head + buf_out_->space); - } - - thread_.reset(new std::thread(&ipc_wrapper_shm::read_thread, this)); - // handler_->on_event(event_handler::EVENT_WRITE, buf_out_->data, buf_size_); - } - void read_thread(void) - { - event_handler* handler = handler_; - - handler->add_ref(); - while (run_) - { - wait_arrive_->wait(); - if (!run_) - break; - if (!shm_->is_first() && sync_shm_->data[DATA_INTER_CMD] == INTER_CMD_EXIT) - break; - - handler->on_event(SCANNER_EVENT_IPC_DATA_RECEIVED, buf_in_->data, buf_in_->bytes); - notify_write_->trigger(); - } - handler->release(); - } - -public: - ipc_wrapper_shm(const char* file, int32_t id - , size_t bytes - , event_handler* handler - , unsigned sent_percent = 50) - : ipc_wrapper(handler), run_(true), shm_(nullptr), sync_shm_(nullptr) - , wait_arrive_(nullptr), wait_sent_(nullptr), notify_write_(nullptr), notify_read_(nullptr) - , buf_in_(nullptr), buf_out_(nullptr), id_(id), buf_out_used_(false), cancel_write_(false) - { - create(file, id, bytes, sent_percent); - } - -protected: - ~ipc_wrapper_shm() - {} - -public: - virtual int32_t write(const char* pack, size_t * bytes, bool kbuf, unsigned timeout = WAIT_INFINITE) override - { - if (!shm_) - return ENOTCONN; - - // invoke in read-thread is not allowed - if(std::this_thread::get_id() == thread_->get_id()) - return EDEADLOCK; - - LOCKER lock(write_lock_); - size_t rest = *bytes; - int32_t ret = 0; - - cancel_write_ = false; - if (kbuf) - { - buf_out_->bytes = rest; - notify_read_->trigger(); - if (wait_sent_->wait(timeout)) - rest = 0; - else - ret = ETIME; - } - else - { - chronograph timer; - while (rest) - { - buf_out_->bytes = rest > buf_out_->space ? buf_out_->space : rest; - memcpy(buf_out_->data, pack, buf_out_->bytes); - notify_read_->trigger(); - - pack += buf_out_->space; - if (!wait_sent_->wait(timeout)) - break; - if (cancel_write_) - break; - - if (rest <= buf_out_->space) - { - rest = 0; - break; - } - rest -= buf_out_->space; - - if (timeout) - { - uint64_t t = timer.elapse_ms(); - if (t >= timeout) - break; - - timeout -= t; - timer.reset(); - } - } - if (cancel_write_) - ret = ECANCELED; - else if (rest) - ret = ETIME; - } - *bytes -= rest; - - return ret; - } - virtual bool cancel_write(void) override - { - cancel_write_ = true; - if (wait_sent_->is_waiting()) - { - wait_sent_->trigger(); - wait_sent_->reset(); // sure ? - } - - return true; - } - virtual bool is_ok(void) override - { - return shm_ != nullptr; - } - virtual bool is_first(void) override - { - return shm_ && shm_->is_first(); - } - - virtual void* get_kbuf(size_t* bytes) override - { - if (!bytes) - return nullptr; - - if (buf_out_used_) - { - *bytes = 0; - - return nullptr; - } - - buf_out_used_ = true; - *bytes = buf_out_->space; - - return buf_out_->data; - } - virtual void release_kbuf(void* buf) override - { - buf_out_used_ = false; - } - virtual void clear_kernel_objects(void) override - { - std::string desc("ipc_wrapper_shm-"); - char id[20] = { 0 }; - - sprintf(id, "%d-", id_); - desc += id; - linux_event::clear_named_event((desc + "wait_arrive").c_str()); - linux_event::clear_named_event((desc + "wait_sent").c_str()); - linux_event::clear_named_event((desc + "notify_write").c_str()); - linux_event::clear_named_event((desc + "notify_read").c_str()); - - shm_->clear_kernel_object(); - } - virtual int32_t stop(void) override - { - run_ = false; - if (shm_) - { - wait_arrive_->trigger(); - if (thread_.get() && thread_->joinable()) - thread_->join(); - thread_.reset(); - - if (is_first()) - { - sync_shm_->data[DATA_INTER_CMD] = INTER_CMD_EXIT; - notify_read_->trigger(); - wait_sent_->wait(100); - } - notify_read_->release(); - notify_read_ = nullptr; - notify_write_->release(); - notify_write_ = nullptr; - wait_arrive_->release(); - wait_arrive_ = nullptr; - wait_sent_->release(); - wait_sent_ = nullptr; - sync_shm_ = nullptr; - buf_in_ = buf_out_ = nullptr; - - shm_->close(); - shm_->release(); - } - shm_ = nullptr; - - return ipc_wrapper::stop(); - } - -}; - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// ipc_wrapper -ipc_wrapper::ipc_wrapper(event_handler* handler) : handler_(handler) -{ - if (handler_) - handler_->add_ref(); -} -ipc_wrapper::~ipc_wrapper() -{} - -void* ipc_wrapper::get_kbuf(size_t* bytes) -{ - if (bytes) - *bytes = 0; - - return nullptr; -} -void ipc_wrapper::release_kbuf(void* buf) -{} -void ipc_wrapper::clear_kernel_objects(void) -{} -bool ipc_wrapper::cancel_write(void) -{ - return false; -} -int32_t ipc_wrapper::stop(void) -{ - if (handler_) - handler_->release(); - handler_ = nullptr; - - return 0; -} - -ipc_wrapper* ipc_wrapper::create_ipc(event_handler* handler, ipc_type type, const char* param) -{ - if (type == IPC_SHARED_MEM) - { - // path-file:id:size[:write-ratio-> percent of size of sent buffer, default is 50, only valid in owner] - std::string file(param); - size_t pos = file.rfind(':'); - std::vector params; - - while(pos != std::string::npos && params.size() < 3) - { - params.push_back(std::stold(file.substr(pos + 1))); - file.erase(pos); - pos = file.rfind(':'); - } - if(params.size() >= 2) - { - params.insert(params.begin(), 50); - pos = params.size(); - - return dynamic_cast(new ipc_wrapper_shm(file.c_str(), params[pos - 1], params[pos - 2], handler, params[pos - 3])); - } - } - return nullptr; -} diff --git a/device/gxx-linux/usb/src/common/ipc_wrapper.h b/device/gxx-linux/usb/src/common/ipc_wrapper.h deleted file mode 100644 index 1263de0..0000000 --- a/device/gxx-linux/usb/src/common/ipc_wrapper.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -// IPC utility -// -// created on 2022-12-02 -// - - -#include "event_monitor.h" - - -class ipc_wrapper : public parent_holder -{ -protected: - event_handler* handler_; - -public: - ipc_wrapper(event_handler* handler); - - enum ipc_type - { - IPC_FILE = 0, // param: path file - IPC_PIPE, // param: pipe name - IPC_NET, // param: dot-ip:port - IPC_SHARED_MEM, // param: path-file:id:size[:write-ratio-> percent of size of sent buffer, default is 50, only valid in owner] - IPC_USB, // param: vid:pid - IPC_COM, // param: COM1 - }; - static ipc_wrapper* create_ipc(event_handler* handler, ipc_type type, const char* param); - -protected: - virtual ~ipc_wrapper(); - -public: - // Function: write content to peer - // - // Parameters: pack - content pack - // - // bytes - [in] bytes of data in 'pack', [out] - bytes of data has sent - // - // kbuf - whether memory 'pack' is from IPC, i.e. return from method get_kbuf() - // - // timeout - time out, in milliseconds - // - // Return: 0 - success - // ENOTCONN - the commuction is not connected, equal to !is_ok() - // EDEADLOCK - calling from current thread is disallowed - // ETIME - time out - // ECANCELED - user cancelled the operation - virtual int32_t write(const char* pack, size_t *bytes, bool kbuf, unsigned timeout = WAIT_INFINITE) = 0; // DON'T call in event_handler::on_event routine, it will be DEAD-LOCK !!! - virtual bool is_ok(void) = 0; // whether the commuction is ready - virtual bool is_first(void) = 0; // whether the communication established by me - - // Function: obtain IPC internal buffer to reduce ONE memory copy for sent data - // - // Parameter: bytes - [in] desired size; [out] - real size - // - // Return: memory pointer if success, or nullptr. call release_kbuf(ptr) if no longer used - virtual void* get_kbuf(size_t* bytes); - virtual void release_kbuf(void* buf); // release the internal buffer returned by get_kbuf - virtual void clear_kernel_objects(void); // clear all kernel objects the IPC used, used to clear exception - virtual bool cancel_write(void); // cancel current write operation - virtual int32_t stop(void) override; // close the connection -}; diff --git a/device/gxx-linux/usb/src/common/json/cJSON.c b/device/gxx-linux/usb/src/common/json/cJSON.c deleted file mode 100644 index cd60134..0000000 --- a/device/gxx-linux/usb/src/common/json/cJSON.c +++ /dev/null @@ -1,794 +0,0 @@ -/* - Copyright (c) 2009 Dave Gamble - - 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. -*/ - -/* cJSON */ -/* JSON parser in C. */ - -#include -#include -#include -#include -#include -#include -#include -#include "cJSON.h" - -static const char *ep; - -const char *cJSON_GetErrorPtr(void) {return ep;} - -static int cJSON_strcasecmp(const char *s1,const char *s2) -{ - if (!s1) return (s1==s2)?0:1;if (!s2) return 1; - for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; - return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); -} - -static void* ask_memory(size_t bytes) -{ -// printf("allocate %u bytes memory in cJSON\n", bytes); - - return malloc(bytes); -} -static void *(*cJSON_malloc)(size_t sz) = ask_memory; -static void (*cJSON_free)(void *ptr) = free; - -static char* cJSON_strdup(const char* str) -{ - size_t len; - char* copy; - - len = strlen(str) + 1; - if (!(copy = (char*)cJSON_malloc(len))) return 0; - memcpy(copy,str,len); - return copy; -} - -void cJSON_InitHooks(cJSON_Hooks* hooks) -{ - if (!hooks) { /* Reset hooks */ - cJSON_malloc = ask_memory; - cJSON_free = free; - return; - } - - cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:ask_memory; - cJSON_free = (hooks->free_fn)?hooks->free_fn:free; -} - -/* Internal constructor. */ -static cJSON *cJSON_New_Item(void) -{ - cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); - if (node) memset(node,0,sizeof(cJSON)); - return node; -} - -/* Delete a cJSON structure. */ -void cJSON_Delete(cJSON *c) -{ - cJSON *next; - while (c) - { - next=c->next; - if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); - if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); - if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); - cJSON_free(c); - c=next; - } -} - -/* Parse the input text to generate a number, and populate the result into item. */ -static const char *parse_number(cJSON *item,const char *num) -{ - double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; - - if (*num=='-') sign=-1,num++; /* Has sign? */ - if (*num=='0') num++; /* is zero */ - if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ - if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ - if (*num=='e' || *num=='E') /* Exponent? */ - { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ - while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ - } - - n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ - - item->valuedouble=n; - item->valueint=(int)n; - item->type=cJSON_Number; - return num; -} - -static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; } - -typedef struct {char *buffer; int length; int offset; } printbuffer; - -static char* ensure(printbuffer *p,int needed) -{ - char *newbuffer;int newsize; - if (!p || !p->buffer) return 0; - needed+=p->offset; - if (needed<=p->length) return p->buffer+p->offset; - - newsize=pow2gt(needed); - newbuffer=(char*)cJSON_malloc(newsize); - if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} - if (newbuffer) memcpy(newbuffer,p->buffer,p->length); - cJSON_free(p->buffer); - p->length=newsize; - p->buffer=newbuffer; - return newbuffer+p->offset; -} - -static int update(printbuffer *p) -{ - char *str; - if (!p || !p->buffer) return 0; - str=p->buffer+p->offset; - return p->offset+strlen(str); -} - -/* Render the number nicely from the given item into a string. */ -static char *print_number(cJSON *item,printbuffer *p) -{ - char *str=0; - double d=item->valuedouble; - if (d==0) - { - if (p) str=ensure(p,2); - else str=(char*)cJSON_malloc(2); /* special case for 0. */ - if (str) strcpy(str,"0"); - } - else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) - { - if (p) str=ensure(p,21); - else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ - if (str) sprintf(str,"%d",item->valueint); - } - else - { - if (p) str=ensure(p,64); - else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ - if (str) - { - if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); - else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); - else sprintf(str,"%f",d); - } - } - return str; -} - -static unsigned parse_hex4(const char *str) -{ - unsigned h=0; - if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; - h=h<<4;str++; - if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; - h=h<<4;str++; - if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; - h=h<<4;str++; - if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; - return h; -} - -/* Parse the input text into an unescaped cstring, and populate item. */ -static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; -static const char *parse_string(cJSON *item,const char *str) -{ - const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; - if (*str!='\"') {ep=str;return 0;} /* not a string! */ - - while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ - - out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ - if (!out) return 0; - - ptr=str+1;ptr2=out; - while (*ptr!='\"' && *ptr) - { - if (*ptr!='\\') *ptr2++=*ptr++; - else - { - ptr++; - switch (*ptr) - { - case 'b': *ptr2++='\b'; break; - case 'f': *ptr2++='\f'; break; - case 'n': *ptr2++='\n'; break; - case 'r': *ptr2++='\r'; break; - case 't': *ptr2++='\t'; break; - case 'u': /* transcode utf16 to utf8. */ - uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ - - if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ - - if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ - { - if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ - uc2=parse_hex4(ptr+3);ptr+=6; - if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ - uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); - } - - len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; - - switch (len) { - case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; - case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; - case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; - case 1: *--ptr2 =(uc | firstByteMark[len]); - } - ptr2+=len; - break; - default: *ptr2++=*ptr; break; - } - ptr++; - } - } - *ptr2=0; - if (*ptr=='\"') ptr++; - item->valuestring=out; - item->type=cJSON_String; - return ptr; -} -char* cJSON_utf8_2_unic(const char* utf8) -{ - char* unic = (char*)malloc(strlen(utf8) * 3 + 8); - unsigned char * cur = unic; - - while (*cur = *utf8++) - { - if ((*cur & 0x0f0) == 0x0e0) - { - if (((unsigned char)utf8[0] & 0x0c0) == 0x80 && - ((unsigned char)utf8[1] & 0x0c0) == 0x80) - { - char* hex = "0123456789ABCDEF"; - unsigned short us = *cur & 0x0f; - us <<= 6; - us += utf8[0] & 0x3f; - us <<= 6; - us += utf8[1] & 0x3f; - - *cur++ = '\\'; - *cur++ = 'u'; - cur[3] = hex[us & 0x0f]; - us >>= 4; - cur[2] = hex[us & 0x0f]; - us >>= 4; - cur[1] = hex[us & 0x0f]; - us >>= 4; - cur[0] = hex[us & 0x0f]; - cur += 3; - utf8 += 2; - } - } - cur++; - } - *cur++ = 0; - - return unic; -} - -/* Render the cstring provided to an escaped version that can be printed. */ -static char *print_string_ptr(const char *str,printbuffer *p) -{ - const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; - - for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; - if (!flag) - { - len=ptr-str; - if (p) out=ensure(p,len+3); - else out=(char*)cJSON_malloc(len+3); - if (!out) return 0; - ptr2=out;*ptr2++='\"'; - strcpy(ptr2,str); - ptr2[len]='\"'; - ptr2[len+1]=0; - return out; - } - - if (!str) - { - if (p) out=ensure(p,3); - else out=(char*)cJSON_malloc(3); - if (!out) return 0; - strcpy(out,"\"\""); - return out; - } - ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} - - if (p) out=ensure(p,len+3); - else out=(char*)cJSON_malloc(len+3); - if (!out) return 0; - - ptr2=out;ptr=str; - *ptr2++='\"'; - while (*ptr) - { - if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; - else - { - *ptr2++='\\'; - switch (token=*ptr++) - { - case '\\': *ptr2++='\\'; break; - case '\"': *ptr2++='\"'; break; - case '\b': *ptr2++='b'; break; - case '\f': *ptr2++='f'; break; - case '\n': *ptr2++='n'; break; - case '\r': *ptr2++='r'; break; - case '\t': *ptr2++='t'; break; - default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ - } - } - } - *ptr2++='\"';*ptr2++=0; - return out; -} -/* Invote print_string_ptr (which is useful) on an item. */ -static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} - -/* Predeclare these prototypes. */ -static const char *parse_value(cJSON *item,const char *value); -static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); -static const char *parse_array(cJSON *item,const char *value); -static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); -static const char *parse_object(cJSON *item,const char *value); -static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); - -/* Utility to jump whitespace and cr/lf */ -static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} - -/* Parse an object - create a new root, and populate. */ -cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) -{ - const char *end=0; - cJSON *c=cJSON_New_Item(); - ep=0; - if (!c) return 0; /* memory fail */ - - end=parse_value(c,skip(value)); - if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ - - /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} - if (return_parse_end) *return_parse_end=end; - return c; -} -/* Default options for cJSON_Parse */ -cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} - -/* Render a cJSON item/entity/structure to text. */ -char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} -char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} - -char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) -{ - printbuffer p; - p.buffer=(char*)cJSON_malloc(prebuffer); - p.length=prebuffer; - p.offset=0; - return print_value(item,0,fmt,&p); - return p.buffer; -} - - -/* Parser core - when encountering text, process appropriately. */ -static const char *parse_value(cJSON *item,const char *value) -{ - if (!value) return 0; /* Fail on null. */ - if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } - if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } - if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } - if (*value=='\"') { return parse_string(item,value); } - if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } - if (*value=='[') { return parse_array(item,value); } - if (*value=='{') { return parse_object(item,value); } - - ep=value;return 0; /* failure. */ -} - -/* Render a value to text. */ -static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) -{ - char *out=0; - if (!item) return 0; - if (p) - { - switch ((item->type)&255) - { - case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} - case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} - case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} - case cJSON_Number: out=print_number(item,p);break; - case cJSON_String: out=print_string(item,p);break; - case cJSON_Array: out=print_array(item,depth,fmt,p);break; - case cJSON_Object: out=print_object(item,depth,fmt,p);break; - } - } - else - { - switch ((item->type)&255) - { - case cJSON_NULL: out=cJSON_strdup("null"); break; - case cJSON_False: out=cJSON_strdup("false");break; - case cJSON_True: out=cJSON_strdup("true"); break; - case cJSON_Number: out=print_number(item,0);break; - case cJSON_String: out=print_string(item,0);break; - case cJSON_Array: out=print_array(item,depth,fmt,0);break; - case cJSON_Object: out=print_object(item,depth,fmt,0);break; - } - } - return out; -} - -/* Build an array from input text. */ -static const char *parse_array(cJSON *item,const char *value) -{ - cJSON *child; - if (*value!='[') {ep=value;return 0;} /* not an array! */ - - item->type=cJSON_Array; - value=skip(value+1); - if (*value==']') return value+1; /* empty array. */ - - item->child=child=cJSON_New_Item(); - if (!item->child) return 0; /* memory fail */ - value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ - if (!value) return 0; - - while (*value==',') - { - cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ - child->next=new_item;new_item->prev=child;child=new_item; - value=skip(parse_value(child,skip(value+1))); - if (!value) return 0; /* memory fail */ - } - - if (*value==']') return value+1; /* end of array */ - ep=value;return 0; /* malformed. */ -} - -/* Render an array to text */ -static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) -{ - char **entries; - char *out=0,*ptr,*ret;int len=5; - cJSON *child=item->child; - int numentries=0,i=0,fail=0; - size_t tmplen=0; - - /* How many entries in the array? */ - while (child) numentries++,child=child->next; - /* Explicitly handle numentries==0 */ - if (!numentries) - { - if (p) out=ensure(p,3); - else out=(char*)cJSON_malloc(3); - if (out) strcpy(out,"[]"); - return out; - } - - if (p) - { - /* Compose the output array. */ - i=p->offset; - ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; - child=item->child; - while (child && !fail) - { - print_value(child,depth+1,fmt,p); - p->offset=update(p); - if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} - child=child->next; - } - ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; - out=(p->buffer)+i; - } - else - { - /* Allocate an array to hold the values for each */ - entries=(char**)cJSON_malloc(numentries*sizeof(char*)); - if (!entries) return 0; - memset(entries,0,numentries*sizeof(char*)); - /* Retrieve all the results: */ - child=item->child; - while (child && !fail) - { - ret=print_value(child,depth+1,fmt,0); - entries[i++]=ret; - if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; - child=child->next; - } - - /* If we didn't fail, try to ask_memory the output string */ - if (!fail) out=(char*)cJSON_malloc(len); - /* If that fails, we fail. */ - if (!out) fail=1; - - /* Handle failure. */ - if (fail) - { - for (i=0;itype=cJSON_Object; - value=skip(value+1); - if (*value=='}') return value+1; /* empty array. */ - - item->child=child=cJSON_New_Item(); - if (!item->child) return 0; - value=skip(parse_string(child,skip(value))); - if (!value) return 0; - child->string=child->valuestring;child->valuestring=0; - if (*value!=':') {ep=value;return 0;} /* fail! */ - value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ - if (!value) return 0; - - while (*value==',') - { - cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ - child->next=new_item;new_item->prev=child;child=new_item; - value=skip(parse_string(child,skip(value+1))); - if (!value) return 0; - child->string=child->valuestring;child->valuestring=0; - if (*value!=':') {ep=value;return 0;} /* fail! */ - value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ - if (!value) return 0; - } - - if (*value=='}') return value+1; /* end of array */ - ep=value;return 0; /* malformed. */ -} - -/* Render an object to text. */ -static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) -{ - char **entries=0,**names=0; - char *out=0,*ptr,*ret,*str;int len=7,i=0,j; - cJSON *child=item->child; - int numentries=0,fail=0; - size_t tmplen=0; - /* Count the number of entries. */ - while (child) numentries++,child=child->next; - /* Explicitly handle empty object case */ - if (!numentries) - { - if (p) out=ensure(p,fmt?depth+4:3); - else out=(char*)cJSON_malloc(fmt?depth+4:3); - if (!out) return 0; - ptr=out;*ptr++='{'; - if (fmt) {*ptr++='\n';for (i=0;ioffset; - len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; - *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; - child=item->child;depth++; - while (child) - { - if (fmt) - { - ptr=ensure(p,depth); if (!ptr) return 0; - for (j=0;joffset+=depth; - } - print_string_ptr(child->string,p); - p->offset=update(p); - - len=fmt?2:1; - ptr=ensure(p,len); if (!ptr) return 0; - *ptr++=':';if (fmt) *ptr++='\t'; - p->offset+=len; - - print_value(child,depth,fmt,p); - p->offset=update(p); - - len=(fmt?1:0)+(child->next?1:0); - ptr=ensure(p,len+1); if (!ptr) return 0; - if (child->next) *ptr++=','; - if (fmt) *ptr++='\n';*ptr=0; - p->offset+=len; - child=child->next; - } - ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; - if (fmt) for (i=0;ibuffer)+i; - } - else - { - /* Allocate space for the names and the objects */ - entries=(char**)cJSON_malloc(numentries*sizeof(char*)); - if (!entries) return 0; - names=(char**)cJSON_malloc(numentries*sizeof(char*)); - if (!names) {cJSON_free(entries);return 0;} - memset(entries,0,sizeof(char*)*numentries); - memset(names,0,sizeof(char*)*numentries); - - /* Collect all the results into our arrays: */ - child=item->child;depth++;if (fmt) len+=depth; - while (child) - { - names[i]=str=print_string_ptr(child->string,0); - entries[i++]=ret=print_value(child,depth,fmt,0); - if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; - child=child->next; - } - - /* Try to allocate the output string */ - if (!fail) out=(char*)cJSON_malloc(len); - if (!out) fail=1; - - /* Handle failure */ - if (fail) - { - for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} -cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} -cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} - -/* Utility for array list handling. */ -static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} -/* Utility for handling references. */ -static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} - -/* Add item to array/object. */ -void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} -void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} -void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} -void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} -void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} - -cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; - if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} -void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} -cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} -void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} - -/* Replace array/object items with new ones. */ -void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;} - newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} -void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; - newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; - if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} -void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} - -/* Create basic types: */ -cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} -cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} -cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} -cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} -cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} -cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} -cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} -cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} - -/* Create Arrays: */ -cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} - -/* Duplication */ -cJSON *cJSON_Duplicate(cJSON *item,int recurse) -{ - cJSON *newitem,*cptr,*nptr=0,*newchild; - /* Bail on bad ptr */ - if (!item) return 0; - /* Create new item */ - newitem=cJSON_New_Item(); - if (!newitem) return 0; - /* Copy over all vars */ - newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; - if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} - if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} - /* If non-recursive, then we're done! */ - if (!recurse) return newitem; - /* Walk the ->next chain for the child. */ - cptr=item->child; - while (cptr) - { - newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ - if (!newchild) {cJSON_Delete(newitem);return 0;} - if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ - else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ - cptr=cptr->next; - } - return newitem; -} - -void cJSON_Minify(char *json) -{ - char *into=json; - while (*json) - { - if (*json==' ') json++; - else if (*json=='\t') json++; /* Whitespace characters. */ - else if (*json=='\r') json++; - else if (*json=='\n') json++; - else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ - else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ - else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ - else *into++=*json++; /* All other characters. */ - } - *into=0; /* and null-terminate. */ -} diff --git a/device/gxx-linux/usb/src/common/referer.cpp b/device/gxx-linux/usb/src/common/referer.cpp deleted file mode 100644 index 799b303..0000000 --- a/device/gxx-linux/usb/src/common/referer.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "referer.h" - -#include - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// refer -refer::refer() : ref_(1) -{ - on_born(); -} -refer::~refer() -{ - on_dead(); -} - -void refer::on_born(void) -{} -void refer::on_dead(void) -{} - -int32_t refer::add_ref(void) -{ - LOCKER lock(mutex_); - - return ++ref_; -} -int32_t refer::release(void) -{ - int32_t ref = 0; - - { - LOCKER lock(mutex_); - ref = --ref_; - } - - if (ref == 0) - delete this; - - return ref; -} - - - - - - - - - - - - - - - - - - - - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// chronograph -#if defined(WIN32) || defined(_WIN64) -// #define WIN32_LEAN_AND_MEAN -#include -#include - -#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 // microseconds from '1601-01-01 00:00:00' to '1970-01-01 00:00:00' - -int gettimeofday(TIMEV* tv, struct timezone* tz) -{ - FILETIME ft = { 0 }; - uint64_t ui64 = 0; - static bool set_tz = true; - - GetSystemTimeAsFileTime(&ft); // 100 ns - from 1601-01-01 00:00:00 - ui64 = ft.dwHighDateTime; - ui64 <<= 32; - ui64 |= ft.dwLowDateTime; - - // convert to microseconds ... - ui64 += 5; - ui64 /= 10; - - // move to 1970-01-01 00:00:00 - ui64 -= DELTA_EPOCH_IN_MICROSECS; - if (tv) - { - tv->tv_sec = ui64 / 1000000; - tv->tv_usec = ui64 % 1000000; - } - - if (tz) - { - if (set_tz) - { - set_tz = false; - _tzset(); - } - tz->tz_minuteswest = _timezone / 60; - tz->tz_dsttime = _daylight; - } - - return 0; -} - -#endif - -chronograph::chronograph() -{ - reset(); -} -chronograph::~chronograph() -{} - -bool chronograph::now(TIMEV* tv) -{ - struct timezone tz = { 0 }; - - return gettimeofday(tv, &tz) == 0; -} -bool chronograph::now(uint64_t* seconds, uint64_t* u_seconds) -{ - TIMEV tv = { 0 }; - struct timezone tz = { 0 }; - - if (gettimeofday(&tv, &tz) == 0) - { - if (seconds) - *seconds = tv.tv_sec; - if (u_seconds) - *u_seconds = tv.tv_usec; - - return true; - } - else - { - return false; - } -} -std::string chronograph::now(bool with_ms/*whether with milliseconds*/) // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false -{ - TIMEV tv = { 0 }; - - if (!chronograph::now(&tv)) - return ""; - - char buf[40] = { 0 }; - time_t t = tv.tv_sec; - struct tm* l = localtime(&t); - - if (with_ms) - sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday - , l->tm_hour, l->tm_min, l->tm_sec, tv.tv_usec); - else - sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday - , l->tm_hour, l->tm_min, l->tm_sec); - - return buf; -} - -uint64_t chronograph::elapse_s(void) -{ - TIMEV tv = { 0 }; - - chronograph::now(&tv); - - return tv.tv_sec - bgn_.tv_sec; -} -uint64_t chronograph::elapse_ms(void) -{ - TIMEV tv = { 0 }; - uint64_t dif = 0; - - chronograph::now(&tv); - dif = SEC_2_MS(tv.tv_sec - bgn_.tv_sec); - dif += tv.tv_usec / MSEC_2_US(1); - dif -= bgn_.tv_usec / MSEC_2_US(1); - - return dif; -} -uint64_t chronograph::elapse_us(void) -{ - TIMEV tv = { 0 }; - uint64_t dif = 0; - - chronograph::now(&tv); - dif = SEC_2_US(tv.tv_sec - bgn_.tv_sec); - dif += tv.tv_usec; - dif -= bgn_.tv_usec; - - return dif; -} -void chronograph::reset() -{ - chronograph::now(&bgn_); -} - - - diff --git a/device/gxx-linux/usb/src/common/sane_cfg.cpp b/device/gxx-linux/usb/src/common/sane_cfg.cpp deleted file mode 100644 index b84c9a3..0000000 --- a/device/gxx-linux/usb/src/common/sane_cfg.cpp +++ /dev/null @@ -1,374 +0,0 @@ -#include "sane_cfg.h" - -#include "json/json.h" - - - - - - - - - - - - - - - - - - - - - - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// sane_cfg_provider: -sane_cfg_provider::sane_cfg_provider() -{} -sane_cfg_provider::~sane_cfg_provider() -{} - -std::string sane_cfg_provider::sane_option_value_get(json* jsn, const char* key, std::string* strval) -{ - std::string type(""), ret(""); - - if (jsn->get_value("type", type)) - { - if (type == "bool") - { - bool v = false; - if (jsn->get_value(key, v)) - ret = std::string((char*)&v, sizeof(v)); - if(strval) - *strval = v ? "true" : "false"; - } - else if (type == "int") - { - int v = 0; - if (jsn->get_value(key, v)) - ret = std::string((char*)&v, sizeof(v)); - if(strval) - *strval = std::to_string(v); - } - else if (type == "float") - { - double v = false; - if (jsn->get_value(key, v)) - ret = std::string((char*)&v, sizeof(v)); - if(strval) - { - char buf[80] = {0}; - sprintf(buf, "%f", v); - *strval = buf; - } - } - else - { - jsn->get_value(key, ret); - if(strval) - *strval = ret; - } - } - - return std::move(ret); -} -bool sane_cfg_provider::sane_option_value_set(json* jsn, void* data, const char* key) -{ - std::string type(""); - bool ret = jsn->get_value("type", type); - - if (ret) - { - if (type == "bool") - { - ret = jsn->set_value(key, *(bool*)data); - } - else if (type == "int") - { - ret = jsn->set_value(key, *(int*)data); - } - else if (type == "float") - { - ret = jsn->set_value(key, *(double*)data); - } - else - { - ret = jsn->set_value(key, (char*)data); - } - } - - return ret; -} - -int32_t sane_cfg_provider::inner_get_config(json* root, void* buf, size_t* len, const char* cfg_name, std::string* strval) -{ - int ret = 0; - std::string val(""); - - if (!len) - return EINVAL; - - if (cfg_name) - { - json* child = nullptr; - if (root->get_value(cfg_name, child) && child) - { - val = sane_cfg_provider::sane_option_value_get(child, "cur", strval); - child->release(); - } - } - else - { - val = root->to_string(); - } - - if (ret == 0) - { - if (*len < val.length()) - { - *len = val.length() + 4; - ret = ENOMEM; - } - else - { - memcpy(buf, val.c_str(), val.length()); - *len = val.length(); - } - } - - return ret; -} - - - - - - - - - - - - - - - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// : - -sane_cfg_mgr::sane_cfg_mgr() -{} -sane_cfg_mgr::~sane_cfg_mgr() -{ - cfg_api_.clear(); - for (auto& v : sane_waiters_) - v->release(); - sane_waiters_.clear(); -} - -json* sane_cfg_mgr::load_all_configs(sane_cfg_provider* prvd) -{ - char * buf = nullptr; - size_t len = 0; - int32_t err = prvd->get_config(buf, &len); - json * jsn = nullptr; - - if (err == ENOMEM) - { - len = ALIGN_INT(len, 8); - buf = (char*)malloc(len); - if (buf) - { - err = prvd->get_config(buf, &len); - if (err == 0) - { - jsn = new json(); - if(!jsn->attach_text(buf)) - { - jsn->release(); - jsn = nullptr; - } - } - free(buf); - } - } - - return jsn; -} - -void sane_cfg_mgr::add_sane_api(const char* name, int ver, sane_cfg_provider* prvd) -{ - if (cfg_api_.count(name) && cfg_api_[name].ver >= ver) - return; - - cfg_api_[name].prvd = prvd; -} -void sane_cfg_mgr::refresh_api(sane_cfg_provider* prvd, std::vector* given) -{ - char * buf = nullptr; - size_t len = 0; - json *jsn = sane_cfg_mgr::load_all_configs(prvd), *child = nullptr; - - if (!jsn) - return; - - if (given) - { - for (auto& v : *given) - { - if (jsn->get_value(v.c_str(), child) && child) - { - int ver = 0; - if (child->get_value("ver", ver)) - add_sane_api(v.c_str(), ver, prvd); - child->release(); - } - } - } - else - { - child = jsn->first_child(); - while (child) - { - int ver = 0; - if (child->get_value("ver", ver)) - add_sane_api(child->key().c_str(), ver, prvd); - child = jsn->next_child(); - } - } - jsn->release(); -} -void sane_cfg_mgr::on_sane_provider_changed(sane_cfg_provider* prvd, bool add) -{ - if (add) - { - refresh_api(prvd); - } - else - { - std::vector lost; - for (auto& v : cfg_api_) - { - if (v.second.prvd == prvd) - lost.push_back(v.first); - } - for (auto& v : lost) - cfg_api_.erase(v); - - char *buf = nullptr; - size_t size = 0, len = 0; - int32_t err = 0; - - for (auto& v : sane_waiters_) - { - refresh_api(v, &lost); - } - } -} -std::string sane_cfg_mgr::get_all_configurations(void) -{ - std::map jsns; - json* all = new json(), * child = nullptr; - std::string text(""); - - for (auto& v : sane_waiters_) - { - json* jsn = sane_cfg_mgr::load_all_configs(v); - if (jsn) - jsns[v] = jsn; - } - for (auto& v : cfg_api_) - { - if (jsns.count(v.second.prvd)) - { - if (jsns[v.second.prvd]->get_value(v.first.c_str(), child) && child) - { - all->set_value(v.first.c_str(), child); - child->release(); - } - } - } - text = all->to_string(); - all->release(); - - for (auto& v : jsns) - v.second->release(); - jsns.clear(); - - return std::move(text); -} - -int sane_cfg_mgr::reg_sane_provider(sane_cfg_provider* prvd) -{ - LOCKER lock(locker_); - if (std::find(sane_waiters_.begin(), sane_waiters_.end(), prvd) == sane_waiters_.end()) - { - sane_waiters_.push_back(prvd); - prvd->add_ref(); - on_sane_provider_changed(prvd, true); - - return 0; - } - - return EEXIST; -} -int sane_cfg_mgr::unreg_sane_provider(sane_cfg_provider* prvd) -{ - LOCKER lock(locker_); - std::vector::iterator it = std::find(sane_waiters_.begin(), sane_waiters_.end(), prvd); - - if (it == sane_waiters_.end()) - return ENOENT; - - sane_waiters_.erase(it); - on_sane_provider_changed(prvd, false); - prvd->release(); - - return 0; -} - -// following APIs' parameters are same as sane_cfg_provider ... -int32_t sane_cfg_mgr::get_config(std::string& text, const char* cfg_name, std::string* str) -{ - if (cfg_name) - { - if (*cfg_name && cfg_api_.count(cfg_name)) - { - size_t len = 0; - int32_t err = cfg_api_[cfg_name].prvd->get_config(nullptr, &len, cfg_name, str); - - if (err == ENOMEM) - { - text.resize(len + 1); - err = cfg_api_[cfg_name].prvd->get_config(&text[0], &len, cfg_name, str); - text.resize(len); - } - - return err; - } - else - return ENOENT; - } - else - { - // get all ... - text = std::move(get_all_configurations()); - - return 0; - } -} -int32_t sane_cfg_mgr::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) -{ - if (cfg_name) - { - if (cfg_api_.count(cfg_name)) - return cfg_api_[cfg_name].prvd->set_config(cfg_name, data, len, afterdo); - else - return ENOENT; - } - else - return EINVAL; -} - diff --git a/device/gxx-linux/usb/src/hardware/hardware.cpp b/device/gxx-linux/usb/src/hardware/hardware.cpp deleted file mode 100644 index 074583a..0000000 --- a/device/gxx-linux/usb/src/hardware/hardware.cpp +++ /dev/null @@ -1,432 +0,0 @@ -#include "hardware.h" - -#include -//{ -// "cis-mode": { -// "category": "base", -// "readonly" : false, -// "affect" : 2, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "CIS����ģʽ", -// "desc" : "����CIS��ɫ���߻ҶȵĹ���ģʽ", -// "type" : "string", -// "cur" : "��ɫ", -// "default" : "��ɫ", -// "size" : 12, -// "range": ["��ɫ", "�Ҷ�"] -// }, -// "cis-dpi": { -// "category": "base", -// "readonly" : false, -// "affect" : 2, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "CIS�ֱ���", -// "desc" : "����CIS�ɼ��ķֱ���", -// "type" : "int", -// "cur" : 200, -// "default" : 200, -// "size" : 4, -// "range": [200, 300] -// }, -// "cis-sample": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "CIS����Ƶ��", -// "desc" : "����CIS��ͷ�����Ĺ���Ƶ��", -// "type" : "int", -// "cur" : 256, -// "default" : 256, -// "size" : 4, -// "range": [128, 256, 512] -// }, -// "frame-h": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "CIS֡�߶�", -// "desc" : "����CISÿһ֡�ĸ߶�", -// "type" : "int", -// "cur" : 12, -// "default" : 12, -// "size" : 4, -// "range": [4, 8, 12, 16] -// }, -// "gain-front": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "��������", -// "desc" : "����CIS���澵ͷ������", -// "type" : "int", -// "cur" : 256, -// "default" : 256, -// "size" : 4, -// "range": [100, 200, 300, 600] -// }, -// "gain-back": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "��������", -// "desc" : "����CIS���澵ͷ������", -// "type" : "int", -// "cur" : 256, -// "default" : 256, -// "size" : 4, -// "range": [100, 200, 300, 600] -// }, -// "offset-front": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "����ƫ��", -// "desc" : "����CIS�����ƫ�ƾ���", -// "type" : "int", -// "cur" : 150, -// "default" : 150, -// "size" : 4, -// "range": [0, 50, 100, 150, 200] -// }, -// "offset-back": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "����ƫ��", -// "desc" : "����CIS�����ƫ�ƾ���", -// "type" : "int", -// "cur" : 150, -// "default" : 150, -// "size" : 4, -// "range": [0, 50, 100, 150, 200] -// }, -// "exposure-f-r": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "�����ɫ�����ع��", -// "desc" : "���������ɫ�������ع�ǿ��", -// "type" : "int", -// "cur" : 0, -// "default" : 0, -// "size" : 4, -// "range": { -// "min": -1000, -// "max": 1000, -// "step": 200 -// } -// }, -// "exposure-f-g": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "������ɫ�����ع��", -// "desc" : "����������ɫ�������ع�ǿ��", -// "type" : "int", -// "cur" : 0, -// "default" : 0, -// "size" : 4, -// "range": { -// "min": -1000, -// "max": 1000, -// "step": 200 -// } -// }, -// "exposure-f-b": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "������ɫ�����ع��", -// "desc" : "����������ɫ�������ع�ǿ��", -// "type" : "int", -// "cur" : 0, -// "default" : 0, -// "size" : 4, -// "range": { -// "min": -1000, -// "max": 1000, -// "step": 200 -// } -// }, -// "exposure-b-r": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "�����ɫ�����ع��", -// "desc" : "�����������ɫ�������ع�ǿ��", -// "type" : "int", -// "cur" : 0, -// "default" : 0, -// "size" : 4, -// "range": { -// "min": -1000, -// "max": 1000, -// "step": 200 -// } -// }, -// "exposure-b-g": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "������ɫ�����ع��", -// "desc" : "���ñ�����ɫ�������ع�ǿ��", -// "type" : "int", -// "cur" : 0, -// "default" : 0, -// "size" : 4, -// "range": { -// "min": -1000, -// "max": 1000, -// "step": 200 -// } -// }, -// "exposure-b-b": { -// "category": "base", -// "readonly" : false, -// "affect" : 0, -// "group" : "base", -// "visible" : false, -// "field" : "cis", -// "pos" : 0, -// "unit" : "None", -// "title" : "������ɫ�����ع��", -// "desc" : "���ñ�����ɫ�������ع�ǿ��", -// "type" : "int", -// "cur" : 0, -// "default" : 0, -// "size" : 4, -// "range": { -// "min": -1000, -// "max": 1000, -// "step": 200 -// } -// }, -//} -static std::string json_text = - "{\"cis-mode\":{\"category\":\"base\",\"readonly\":false,\"affect\":2,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"CIS\\u5de5\\u4f5c\\u6a21\\u5f0f\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u5f69\\u8272\\u6216\\u8005\\u7070\\u5ea6\\u7684\\u5de5\\u4f5c\\u6a21\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u5f69\\u8272\",\"default\":\"\\u5f69\\u8272\",\"size\":12,\"range\":[\"\\u5f69\\u8272\",\"\\u7070\\u5ea6\"]},\"cis-dpi\":{\"category\":\"base\",\"readonly\":false,\"affect\":2,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"CIS\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u91c7\\u96c6\\u7684\\u5206\\u8fa8\\u7387\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":[200,300]},\"cis-sample\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"CIS\\u91c7\\u6837\\u9891\\u7387\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u955c\\u5934\\u91c7\\u6837\\u7684\\u5de5\\u4f5c\\u9891\\u7387\",\"type\":\"int\",\"cur\":256,\"default\":256,\"size\":4,\"range\":[128,256,512]},\"frame-h\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"CIS\\u5e27\\u9ad8\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u6bcf\\u4e00\\u5e27\\u7684\\u9ad8\\u5ea6\",\"type\":\"int\",\"cur\":12,\"default\":12,\"size\":4,\"range\":[4,8,12,16]},\"gain-front\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u589e\\u76ca\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u6b63\\u9762\\u955c\\u5934\\u7684\\u589e\\u76ca\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":[100,200,300,600]},\"gain-back\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u589e\\u76ca\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u80cc\\u9762\\u955c\\u5934\\u7684\\u589e\\u76ca\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":[100,200,300,600]},\"offset-front\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u504f\\u79fb\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u6b63\\u9762\\u7684\\u504f\\u79fb\\u8ddd\\u79bb\",\"type\":\"int\",\"cur\":150,\"default\":150,\"size\":4,\"range\":[0,50,100,150,200]},\"offset-back\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u504f\\u79fb\",\"desc\":\"\\u8bbe\\u7f6eCIS\\u80cc\\u9762\\u7684\\u504f\\u79fb\\u8ddd\\u79bb\",\"type\":\"int\",\"cur\":150,\"default\":150,\"size\":4,\"range\":[0,50,100,150,200]},\"exposure-f-r\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u7ea2\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u6b63\\u9762\\u7ea2\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-f-g\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u7eff\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u6b63\\u9762\\u7eff\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-f-b\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u6b63\\u9762\\u84dd\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u6b63\\u9762\\u84dd\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-b-r\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u7ea2\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u6b63\\u80cc\\u9762\\u7ea2\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-b-g\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u7eff\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u80cc\\u9762\\u7eff\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}},\"exposure-b-b\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":false,\"field\":\"cis\",\"pos\":0,\"ver\":1,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u84dd\\u8272\\u5206\\u91cf\\u66dd\\u5149\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u80cc\\u9762\\u84dd\\u8272\\u5206\\u91cf\\u7684\\u66dd\\u5149\\u5f3a\\u5ea6\",\"type\":\"int\",\"cur\":0,\"default\":0,\"size\":4,\"range\":{\"min\":-1000,\"max\":1000,\"step\":200}}}"; - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// class hardware -hardware::hardware() : cfg_(new json()) -{ - printf("parse hardware json: %s\n", cfg_->attach_text(&json_text[0]) ? "OK" : "Failed"); - memset(&api_, 0, sizeof(api_)); -} -hardware::~hardware() -{ - cfg_->release(); -} - -int32_t hardware::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) -{ - return inner_get_config(cfg_, buf, len, cfg_name, strval); -} -int32_t hardware::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) -{ - int ret = ENOENT; - json* child = nullptr; - - if (cfg_->get_value(cfg_name, child) && child) - { - ret = set(cfg_name, data, len); - if (ret == 0 || ret == EUCLEAN) - { - sane_option_value_set(child, data); - if (afterdo) - { - child->get_value("affect", ret); - *afterdo = ret; - ret = 0; - } - } - child->release(); - } - - return ret; -} - -void hardware::set_api(LPCISAPI api) -{ - memset(&api_, 0, sizeof(api_)); - if (api) - memcpy(&api_, api, sizeof(api_)); -} - -int32_t hardware::set(const char* name, void* data, size_t* len) -{ - int32_t ret = ENOENT; - int val = *(int*)data; - std::string n(name); - CIS_API api = CIS_API(); - - if (n == "cis-mode") - { - int clr = 1; - std::string gray("\xE7\x81\xB0\xE5\xBA\xA6"), - color("\xE5\xBD\xA9\xE8\x89\xB2"); - - n = std::string((char*)data); - if (n == gray) // �Ҷ� - { - clr = 0; - } - else - { - if (n != color) - { - ret = EUCLEAN; - strcpy((char*)data, color.c_str()); - *len = color.length(); - } - } - - val = clr; - if (api_.set_color_mode) - { - ret = 0; - api_.set_color_mode(&val); - if (val != clr) - { - if (val == 0) - { - strcpy((char*)data, gray.c_str()); - *len = gray.length(); - } - else - { - strcpy((char*)data, color.c_str()); - *len = color.length(); - } - ret = EUCLEAN; - } - } - } - else if (n == "cis-dpi") - { - api = api_.set_dpi; - } - else if (n == "cis-sample") - { - api = api_.set_sample; - } - else if (n == "frame-h") - { - api = api_.set_frame_height; - } - else if (n == "gain-front") - { - api = api_.set_gain_front; - } - else if (n == "gain-back") - { - api = api_.set_gain_back; - } - else if (n == "offset-front") - { - api = api_.set_offset_front; - } - else if (n == "offset-back") - { - api = api_.set_offset_back; - } - else if (n == "exposure-f-r") - { - api = api_.set_exposure_front_red; - } - else if (n == "exposure-f-g") - { - api = api_.set_exposure_front_green; - } - else if (n == "exposure-f-b") - { - api = api_.set_exposure_front_blue; - } - else if (n == "exposure-b-r") - { - api = api_.set_exposure_back_red; - } - else if (n == "exposure-b-g") - { - api = api_.set_exposure_back_green; - } - else if (n == "exposure-b-b") - { - api = api_.set_exposure_back_blue; - } - - if (api) - { - ret = 0; - api(&val); - if (val != *(int*)data) - { - *(int*)data = val; - ret = EUCLEAN; - } - } - - return ret; -} diff --git a/device/gxx-linux/usb/src/hardware/hardware.h b/device/gxx-linux/usb/src/hardware/hardware.h deleted file mode 100644 index a257def..0000000 --- a/device/gxx-linux/usb/src/hardware/hardware.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -// image process interface classes -// -// created on 2023-04-19 -// - -#include -#include -#include -#include - -class json; - -#define CIS_API std::function // return error code, set real value to parameter if in-value was not exact - -typedef struct _cis_api -{ - CIS_API set_color_mode; - CIS_API set_dpi; - CIS_API set_sample; - CIS_API set_frame_height; - CIS_API set_gain_front; - CIS_API set_gain_back; - CIS_API set_offset_front; - CIS_API set_offset_back; - CIS_API set_exposure_front_red; - CIS_API set_exposure_front_green; - CIS_API set_exposure_front_blue; - CIS_API set_exposure_back_red; - CIS_API set_exposure_back_green; - CIS_API set_exposure_back_blue; -}CISAPI, *LPCISAPI; - -class hardware : public sane_cfg_provider -{ - json* cfg_; - CISAPI api_; - - int32_t set(const char* name, void* data, size_t* len); - -public: - hardware(); - -protected: - ~hardware(); - - // sane_cfg_provider -public: - virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name = nullptr, std::string* strval = nullptr) override; - virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override; - -public: - void set_api(LPCISAPI api); -}; - diff --git a/device/gxx-linux/usb/src/usbdevice.cpp b/device/gxx-linux/usb/src/usbdevice.cpp index 990beb2..83cf57e 100644 --- a/device/gxx-linux/usb/src/usbdevice.cpp +++ b/device/gxx-linux/usb/src/usbdevice.cpp @@ -11,12 +11,20 @@ #include #include -#include "log_util.h" #ifdef ASYNC_EP #include "common/sys_util.h" -#include "common/json/json.h" -#include "hardware/hardware.h" -#include "commondef.h" +#include "common/json/gb_json.h" +#include "common/log_util.h" +#include "scanner/async_scanner.h" + +#ifdef TEMPORARY_API +int32_t (*scan_start)(void) = nullptr; +int32_t (*scan_stop)(void) = nullptr; +int32_t (*set_dpi)(int*, int*) = nullptr; +int32_t (*set_scan_num)(int) = nullptr; +int32_t (*set_image_receiver)(void(*rcv)(int data_type, void* data, size_t w, size_t h, int, int, size_t paper_ind, paper_side side, clr_channel clr, img_status status, bool img_new, bool img_over, void* param), void* param) = nullptr; +#endif + #endif #define CONFIG_VALUE 1 @@ -65,6 +73,29 @@ static std::shared_ptr bulk_read_; static std::shared_ptr int_sent_; const int UsbDevice::cacheSize = 64*1024; +#ifdef TEMPORARY_API +static UsbDevice* inst = nullptr; +int32_t call_start_scan(void) +{ + return inst->start_scan(); +} +int32_t call_stop_scan(void) +{ + return inst->stop_scan(); +} +int32_t call_set_dpi(int* dpix, int* dpiy) +{ + return inst->set_dpi(dpix, dpiy); +} +int32_t call_set_scan_num(int num) +{ + return inst->set_scan_num(num); +} +int32_t call_set_image_receiver(void(*rcv)(int data_type, void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel clr, img_status status, bool img_new, bool img_over, void* param), void* param) +{ + return inst->set_img_receiver((void*)rcv, param); +} +#endif int camtp_load_config_file(camtp_ctx * context, const char * conffile) @@ -315,23 +346,11 @@ void UsbDevice::fill_dev_descriptor(camtp_ctx * ctx, usb_gadget * usbctx,struct return; } -#ifdef ASYNC_EP -static void print_mem_usage(const char* desc) -{ - uint64_t size = sys_util::get_memory_usage("scan"); - - printf("\n--Memory usage of %s: %s--\n", desc, sys_util::format_readable_bytes(size).c_str()); -} -static void image_receiver(MemoryPtr data, bool img, void* param) -{ - ((UsbDevice*)param)->save_image(data, img); -} -#endif UsbDevice::UsbDevice(std::function handler, std::function call_back) : b_connected(false) , connect_call(call_back) #ifdef ASYNC_EP -, usb_(nullptr), cfg_(nullptr), scan_over_pack_(nullptr), scan_id_(0) +, ascan_(nullptr) #endif { camtp_context.reset(new camtp_ctx); @@ -339,59 +358,22 @@ UsbDevice::UsbDevice(std::function dyn_mem_ptr - { - LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); - uint32_t consume = 0, want = 0; - - if(!used) - used = &consume; - *used = data->get_rest(); - - return handle_bulk_cmd(pack, used, required); - }; - - auto ctrl_unhandle = [&](struct usb_functionfs_event* pev) -> dyn_mem_ptr - { - return unhandled_ep0(pev); - }; - - auto on_connect = [&](bool conn) -> void - { - static bool reg_cb = true; - - if(reg_cb) - { - uint64_t cb[] = {(uint64_t)image_receiver, (uint64_t)this}; - ctrl_handler(-1, (usb_ctrlrequest*)-1, (unsigned char*)cb); - - reg_cb = false; - } - - connect_call(conn); - }; + ::inst = this; + ::scan_start = call_start_scan; + ::scan_stop = call_stop_scan; + ::set_dpi = call_set_dpi; + ::set_scan_num = call_set_scan_num; + ::set_image_receiver = call_set_image_receiver; thread_pool *t = new thread_pool(this); - print_mem_usage("new thread_pool"); t->thread_new(&UsbDevice::do_system_command, R"(echo linaro | sudo -S sh -c "echo fe900000.dwc3 > /opt/cfg/usb_gadget/g1/UDC")"); camtp_load_config_file(camtp_context.get(), ""); - // std::this_thread::sleep_for(std::chrono::milliseconds(50)); usb_ctx = init_usb_camtp_gadget(camtp_context.get()); - print_mem_usage("init_usb_camtp_gadget"); if(usb_ctx && usb_ctx->usb_device >= 0) { get_system_output(R"(echo linaro | sudo -S sh -c "chmod 777 /dev/ffs-camtp -R")"); init_eps(usb_ctx, camtp_context->usb_cfg.usb_functionfs_mode, false); - print_mem_usage("init_eps"); - - usb_ = new async_usb_gadget(usb_ctx, ctrl_unhandle, bulk_handle, on_connect); - print_mem_usage("new async_usb_gadget"); + ascan_ = new async_scanner(usb_ctx); } t->thread_stop(); t->release(); @@ -406,15 +388,15 @@ UsbDevice::UsbDevice(std::functionstop(); - usb_->release(); + ascan_->stop(); + ascan_->release(); + ascan_ = nullptr; } - if(cfg_) - cfg_->release(); +#else + pthread_cancel(thread_main.native_handle()); #endif } @@ -1400,771 +1382,64 @@ init_eps_error: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // #ifdef ASYNC_EP - -// C2-B0-AF-79-75-D6 -//static std::string img_opt1("{\"is-multiout\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u591a\\u6d41\\u8f93\\u51fa\",\"desc\":\"\\u540c\\u65f6\\u8f93\\u51fa\\u591a\\u79cd\\u989c\\u8272\\u6a21\\u5f0f\\u7684\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"multiout-type\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u591a\\u6d41\\u8f93\\u51fa\\u7c7b\\u578b\",\"desc\":\"\\u9009\\u62e9\\u591a\\u6d41\\u8f93\\u51fa\\u7684\\u7c7b\\u578b\",\"type\":\"string\",\"cur\":\"\\u5f69\\u8272+\\u7070\\u5ea6+\\u9ed1\\u767d\",\"default\":\"\\u5f69\\u8272+\\u7070\\u5ea6+\\u9ed1\\u767d\",\"size\":32,\"range\":[\"\\u5f69\\u8272+\\u7070\\u5ea6+\\u9ed1\\u767d\",\"\\u5f69\\u8272+\\u7070\\u5ea6\",\"\\u5f69\\u8272+\\u9ed1\\u767d\",\"\\u7070\\u5ea6+\\u9ed1\\u767d\"],\"depend_or\":[\"is-multiout==true\"]},\"mode\":{\"category\":\"base\",\"readonly\":false,\"affect\":6,\"group\":\"base\",\"visible\":true,\"field\":\"Hardware\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u989c\\u8272\\u6a21\\u5f0f\",\"desc\":\"\\u9009\\u62e9\\u8272\\u5f69\\u6a21\\u5f0f\",\"type\":\"string\",\"cur\":\"24\\u4f4d\\u5f69\\u8272\",\"default\":\"24\\u4f4d\\u5f69\\u8272\",\"size\":32,\"range\":[\"24\\u4f4d\\u5f69\\u8272\",\"256\\u7ea7\\u7070\\u5ea6\",\"\\u9ed1\\u767d\",\"\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"],\"depend_or\":[\"is-multiout!=true\"]},\"binary-threshold\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u9ed1\\u767d\\u56fe\\u50cf\\u9608\\u503c\",\"desc\":\"\\u9ad8\\u4e8e\\u8be5\\u9608\\u503c\\u4e3a1��\\u767d����\\u4f4e\\u4e8e\\u8be5\\u9608\\u503c\\u4e3a0��\\u9ed1��\",\"type\":\"int\",\"cur\":127,\"default\":127,\"size\":4,\"range\":{\"min\":0,\"max\":255,\"step\":1},\"depend_or\":[\"is-multiout==true\",\"mode==\\u9ed1\\u767d\"]},\"reverse-bw\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u9ed1\\u767d\\u56fe\\u50cf\\u53cd\\u8272\\u8f93\\u51fa\",\"desc\":\"\\u8f93\\u51fa\\u7684\\u9ed1\\u767d\\u56fe\\u50cf\\u4ee5��1��\\u4ee3\\u8868\\u9ed1\\u8272����0��\\u4ee3\\u8868\\u767d\\u8272\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"is-multiout==true\",\"mode==\\u9ed1\\u767d\"]},\"filter\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u7070\\u5ea6\\u6216\\u9ed1\\u767d\\u56fe\\u50cf - \\u9664\\u8272\\u4e0e\\u589e\\u5f3a\",\"desc\":\"\\u6d88\\u9664\\u6216\\u589e\\u5f3a\\u6307\\u5b9a\\u8272\\u5f69\",\"type\":\"string\",\"cur\":\"\\u4e0d\\u9664\\u8272\",\"default\":\"\\u4e0d\\u9664\\u8272\",\"size\":24,\"range\":[\"\\u4e0d\\u9664\\u8272\",\"\\u9664\\u7ea2\\u8272\",\"\\u9664\\u7eff\\u8272\",\"\\u9664\\u84dd\\u8272\",\"\\u7ea2\\u8272\\u589e\\u5f3a\",\"\\u7eff\\u8272\\u589e\\u5f3a\",\"\\u84dd\\u8272\\u589e\\u5f3a\"],\"depend_and\":[\"is-multiout!=true\",\"mode!=24\\u4f4d\\u5f69\\u8272\",\"!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"is-rid-multiout-red\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"24\\u4f4d\\u5f69\\u8272\\u56fe\\u50cf - \\u591a\\u6d41\\u8f93\\u51fa\\u9664\\u7ea2\",\"desc\":\"\\u540c\\u65f6\\u8f93\\u51fa\\u5f69\\u8272\\u56fe\\u50cf\\u548c\\u7070\\u5ea6\\u9664\\u7ea2\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"is-multiout!=true\",\"mode!=256\\u7ea7\\u7070\\u5ea6\",\"!=\\u9ed1\\u767d\",\"!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"is-rid-answer-sheet-red\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"24\\u4f4d\\u5f69\\u8272\\u56fe\\u50cf - \\u7b54\\u9898\\u5361\\u9664\\u7ea2\",\"desc\":\"\\u8f93\\u51fa\\u9664\\u7ea2\\u5f69\\u8272\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"is-multiout!=true\",\"mode!=256\\u7ea7\\u7070\\u5ea6\",\"!=\\u9ed1\\u767d\",\"!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"is-erase-bkg\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u80cc\\u666f\\u79fb\\u9664\",\"desc\":\"\\u79fb\\u9664\\u6587\\u7a3f\\u80cc\\u666f\\u5e95\\u8272\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"is-multiout!=true\",\"mode!=256\\u7ea7\\u7070\\u5ea6\",\"!=\\u9ed1\\u767d\",\"!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"bkg-color-range\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u80cc\\u666f\\u8272\\u5f69\\u6d6e\\u52a8\\u8303\\u56f4\",\"desc\":\"\\u4e0e\\u80cc\\u666f\\u5e95\\u8272\\u504f\\u5dee\\u5728\\u8be5\\u503c\\u8303\\u56f4\\u5185\\u7684\\u989c\\u8272��\\u90fd\\u5c06\\u88ab\\u79fb\\u9664\",\"type\":\"int\",\"cur\":20,\"default\":20,\"size\":4,\"range\":{\"min\":1,\"max\":128,\"step\":1},\"depend_or\":[\"is-erase-bkg==true\"]},\"sharpen\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u9510\\u5316\\u4e0e\\u6a21\\u7cca\",\"desc\":\"\\u9009\\u62e9\\u9510\\u5316\\u6548\\u679c\\u6216\\u6a21\\u7cca\\u6548\\u679c\",\"type\":\"string\",\"cur\":\"\\u65e0\",\"default\":\"\\u65e0\",\"size\":24,\"range\":[\"\\u65e0\",\"\\u9510\\u5316\",\"\\u8fdb\\u4e00\\u6b65\\u9510\\u5316\",\"\\u6a21\\u7cca\",\"\\u8fdb\\u4e00\\u6b65\\u6a21\\u7cca\"],\"depend_and\":[\"is-multiout!=true\",\"mode!=\\u9ed1\\u767d\",\"!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"is-rid-morr\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u53bb\\u9664\\u6469\\u5c14\\u7eb9\",\"desc\":\"\\u53bb\\u9664\\u56fe\\u50cf\\u4e2d\\u7684\\u6469\\u5c14\\u7eb9\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"is-multiout!=true\",\"mode!=\\u9ed1\\u767d\",\"!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"is-rid-grid\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u9664\\u7f51\\u7eb9\",\"desc\":\"\\u53bb\\u9664\\u56fe\\u50cf\\u4e2d\\u7684\\u7f51\\u7eb9\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"is-multiout!=true\",\"mode!=\\u9ed1\\u767d\",\"!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"is-err-extension\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u9519\\u8bef\\u6269\\u6563\",\"desc\":\"\\u4ee5\\u70b9\\u9635\\u5f62\\u5f0f\\u6784\\u5efa\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"mode==\\u9ed1\\u767d\"]},\"is-noise-optimize\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u9ed1\\u767d\\u56fe\\u50cf\\u566a\\u70b9\\u4f18\\u5316\",\"desc\":\"\\u53bb\\u9664\\u56fe\\u50cf\\u4e2d\\u7684\\u5b64\\u7acb\\u9ed1\\u70b9\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"mode==\\u9ed1\\u767d\"]},\"noise-size\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u566a\\u70b9\\u4f18\\u5316\\u5c3a\\u5bf8\",\"desc\":\"\\u8bbe\\u7f6e\\u9700\\u8981\\u53bb\\u9664\\u7684\\u9ed1\\u8272\\u5b64\\u7acb\\u70b9\\u7684\\u8fde\\u901a\\u4e2a\\u6570\",\"type\":\"int\",\"cur\":30,\"default\":30,\"size\":4,\"range\":{\"min\":10,\"max\":50,\"step\":1},\"depend_or\":[\"is-noise-optimize==true\"]},\"blank-sensitivity\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\u7075\\u654f\\u5ea6\",\"desc\":\"\\u6570\\u503c\\u8d8a\\u5927��\\u5219\\u8d8a\\u5bb9\\u6613\\u8df3\\u8fc7\",\"type\":\"int\",\"cur\":50,\"default\":50,\"size\":4,\"range\":{\"min\":1,\"max\":100,\"step\":1},\"depend_or\":[\"page==\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875��\\u901a\\u7528��\",\"==\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875��\\u53d1\\u7968\\u7eb8��\"]},\"fold-type\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u5bf9\\u6298\\u6a21\\u5f0f\",\"desc\":\"\",\"type\":\"string\",\"cur\":\"\\u5de6\\u53f3\\u5bf9\\u6298\",\"default\":\"\\u5de6\\u53f3\\u5bf9\\u6298\",\"size\":50,\"range\":[\"\\u5de6\\u53f3\\u5bf9\\u6298\",\"\\u4e0a\\u4e0b\\u5bf9\\u6298\",\"\\u81ea\\u52a8\\u5bf9\\u6298\"],\"depend_or\":[\"page==\\u5bf9\\u6298\"]},\"is-exchange\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u4ea4\\u6362\\u6b63\\u53cd\\u9762\",\"desc\":\"\\u4ea4\\u6362\\u6bcf\\u5f20\\u6587\\u7a3f\\u7684\\u6b63\\u53cd\\u9762\\u51fa\\u56fe\\u987a\\u5e8f\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"page!=\\u5355\\u9762\"]},\"is-custom-gamma\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"light\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u542f\\u7528\\u8272\\u8c03\\u66f2\\u7ebf\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u56fe\\u50cf\\u8272\\u8c03\\u6548\\u679c\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},"); -//static std::string img_opt2("\"brightness\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"light\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u4eae\\u5ea6\\u503c\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u50cf\\u4eae\\u5ea6\",\"type\":\"int\",\"cur\":128,\"default\":128,\"size\":4,\"range\":{\"min\":1,\"max\":255,\"step\":1},\"depend_and\":[\"is-custom-gamma==false\"]},\"contrast\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"light\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u5bf9\\u6bd4\\u5ea6\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u50cf\\u5bf9\\u6bd4\\u5ea6\",\"type\":\"int\",\"cur\":4,\"default\":4,\"size\":4,\"range\":{\"min\":1,\"max\":7,\"step\":1},\"depend_and\":[\"is-custom-gamma==false\"]},\"gamma\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"light\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u4f3d\\u9a6c\\u503c\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u50cf\\u4f3d\\u739b\\u503c\",\"type\":\"float\",\"cur\":1.000000,\"default\":1.000000,\"size\":4,\"range\":{\"min\":0.010000,\"max\":5.000000,\"step\":0.499000},\"depend_and\":[\"is-custom-gamma==false\"]},\"color-correction\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8272\\u504f\\u6821\\u6b63\",\"desc\":\"\\u8272\\u5f69\\u8fd8\\u539f\\u5ea6\\u77eb\\u6b63\\u529f\\u80fd\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"is-anti-skew\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u81ea\\u52a8\\u7ea0\\u504f\",\"desc\":\"\\u81ea\\u52a8\\u7ea0\\u6b63\\u6b6a\\u659c\\u9001\\u5165\\u7684\\u6587\\u7a3f\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4,\"depend_or\":[\"page!=\\u5bf9\\u6298\"]},\"is-split\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u56fe\\u50cf\\u62c6\\u5206\",\"desc\":\"\\u81ea\\u52a8\\u62c6\\u5206\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"page!=\\u5bf9\\u6298\",\"!=\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875��\\u53d1\\u7968\\u7eb8��\",\"!=\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875��\\u901a\\u7528��\"]},\"is-erase-black-frame\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u6d88\\u9664\\u9ed1\\u6846\",\"desc\":\"\\u6d88\\u9664\\u6587\\u7a3f\\u8303\\u56f4\\u5916\\u7684\\u9ed1\\u8272\\u80cc\\u666f\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"bkg-fill-mode\":{\"category\":\"advanced\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u80cc\\u666f\\u586b\\u5145\\u65b9\\u5f0f\",\"desc\":\"\\u9009\\u62e9\\u80cc\\u666f\\u586b\\u5145\\u65b9\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"default\":\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"size\":40,\"range\":[\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"\\u51f9\\u591a\\u8fb9\\u5f62\"],\"depend_or\":[\"is-erase-black-frame==true\"]},\"is-fill-color\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8272\\u5f69\\u586b\\u5145\",\"desc\":\"\\u542f\\u7528\\u540e\\u9ed1\\u6846\\u90e8\\u5206\\u5c06\\u586b\\u5145\\u4e3a\\u6587\\u7a3f\\u5e95\\u8272\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"is-erase-black-frame==true\"]},\"threshold\":{\"category\":\"advanced\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u9608\\u503c\",\"desc\":\"\\u6587\\u7a3f\\u5e95\\u8272\\u4e0e\\u9ed1\\u8272\\u80cc\\u666f\\u7070\\u5ea6\\u503c\\u7684\\u5dee\\u503c\\u5927\\u4e8e\\u8be5\\u503c��\\u624d\\u4f1a\\u88ab\\u8bc6\\u522b\\u4e3a\\u6587\\u7a3f\",\"type\":\"int\",\"cur\":40,\"default\":40,\"size\":4,\"range\":{\"min\":30,\"max\":50,\"step\":1},\"depend_or\":[\"is-erase-black-frame==true\",\"paper==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"is-anti-skew==true\"]},\"anti-noise-level\":{\"category\":\"advanced\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u80cc\\u666f\\u6297\\u566a\\u7b49\\u7ea7\",\"desc\":\"\\u80fd\\u591f\\u5bb9\\u5fcd\\u7684\\u80cc\\u666f\\u6742\\u8272\\u6761\\u7eb9\\u7684\\u5bbd\\u5ea6\",\"type\":\"int\",\"cur\":8,\"default\":8,\"size\":4,\"range\":{\"min\":1,\"max\":20,\"step\":1},\"depend_or\":[\"is-erase-black-frame==true\",\"paper==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"is-anti-skew==true\"]},\"margin\":{\"category\":\"advanced\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8fb9\\u7f18\\u7f29\\u8fdb\",\"desc\":\"\\u5bfb\\u627e\\u6587\\u7a3f\\u8fb9\\u7f18\\u65f6\\u5bf9\\u8fb9\\u7f18\\u7684\\u4fb5\\u5165\\u7a0b\\u5ea6\",\"type\":\"int\",\"cur\":5,\"default\":5,\"size\":4,\"range\":{\"min\":5,\"max\":30,\"step\":1},\"depend_or\":[\"is-erase-black-frame==true\",\"paper==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"is-anti-skew==true\"]},\"is-dark-sample\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u6df1\\u8272\\u6837\\u5f20\",\"desc\":\"\\u542f\\u7528\\u8be5\\u6a21\\u5f0f\\u9632\\u6b62\\u6df1\\u8272\\u5e95\\u8272\\u7684\\u6587\\u7a3f\\u56fe\\u50cf\\u88ab\\u8bef\\u5904\\u7406\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"page!=\\u5bf9\\u6298\",\"is-erase-black-frame!=true\",\"paper!=\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"is-anti-skew!=true\"]},\"is-anti-permeate\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u9632\\u6b62\\u6e17\\u900f\",\"desc\":\"\\u9632\\u6b62\\u80cc\\u9762\\u56fe\\u6848\\u6e17\\u900f\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"permeate-level\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u9632\\u6b62\\u6e17\\u900f\\u7b49\\u7ea7\",\"desc\":\"\\u9009\\u62e9\\u9632\\u6b62\\u6e17\\u900f\\u7684\\u7b49\\u7ea7\",\"type\":\"string\",\"cur\":\"\\u8f83\\u5f31\",\"default\":\"\\u8f83\\u5f31\",\"size\":16,\"range\":[\"\\u5f31\",\"\\u8f83\\u5f31\",\"\\u4e00\\u822c\",\"\\u8f83\\u5f3a\",\"\\u5f3a\"],\"depend_or\":[\"is-anti-permeate==true\"]},\"is-rid-hole-l\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u7a7f\\u5b54\\u79fb\\u9664��\\u5de6\\u4fa7\",\"desc\":\"\\u7a7f\\u5b54\\u5728\\u7eb8\\u5f20\\u4e0a\\u7684\\u5de6\\u4fa7\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"search-hole-range-l\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u5de6\\u4fa7\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"desc\":\"\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"type\":\"float\",\"cur\":0.100000,\"default\":0.100000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":0.500000,\"step\":0.050000},\"depend_and\":[\"is-rid-hole-l==true\"]},\"is-rid-hole-r\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u7a7f\\u5b54\\u79fb\\u9664��\\u53f3\\u4fa7\",\"desc\":\"\\u7a7f\\u5b54\\u5728\\u7eb8\\u5f20\\u4e0a\\u7684\\u53f3\\u4fa7\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"search-hole-range-r\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u53f3\\u4fa7\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"desc\":\"\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"type\":\"float\",\"cur\":0.100000,\"default\":0.100000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":0.500000,\"step\":0.050000},\"depend_and\":[\"is-rid-hole-r==true\"]},\"is-rid-hole-t\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u7a7f\\u5b54\\u79fb\\u9664��\\u4e0a\\u4fa7\",\"desc\":\"\\u7a7f\\u5b54\\u5728\\u7eb8\\u5f20\\u7684\\u4e0a\\u90e8\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"search-hole-range-t\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u4e0a\\u4fa7\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"desc\":\"\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"type\":\"float\",\"cur\":0.100000,\"default\":0.100000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":0.500000,\"step\":0.050000},\"depend_and\":[\"is-rid-hole-t==true\"]},\"is-rid-hole-b\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u7a7f\\u5b54\\u79fb\\u9664��\\u4e0b\\u4fa7\",\"desc\":\"\\u7a7f\\u5b54\\u5728\\u7eb8\\u5f20\\u7684\\u4e0b\\u90e8\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"search-hole-range-b\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"imgproc\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u4e0b\\u4fa7\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"desc\":\"\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"type\":\"float\",\"cur\":0.100000,\"default\":0.100000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":0.500000,\"step\":0.050000},\"depend_and\":[\"is-rid-hole-b==true\"]},\"direction\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u6587\\u7a3f\\u65b9\\u5411\",\"desc\":\"\\u8bbe\\u7f6e\\u56fe\\u50cf\\u7684\\u65b9\\u5411\",\"type\":\"string\",\"cur\":\"0��\",\"default\":\"0��\",\"size\":40,\"range\":[\"0��\",\"90��\",\"180��\",\"-90��\",\"\\u81ea\\u52a8\\u6587\\u672c\\u65b9\\u5411\\u8bc6\\u522b��\"]},\"is-rotate-bkg-180\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u80cc\\u9762\\u65cb\\u8f6c180��\",\"desc\":\"\\u80cc\\u9762\\u626b\\u63cf\\u7684\\u56fe\\u50cf\\u65cb\\u8f6c180��\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"page!=\\u5355\\u9762\",\"!=\\u5bf9\\u6298\",\"direction!=\\u81ea\\u52a8\\u6587\\u672c\\u65b9\\u5411\\u8bc6\\u522b��\"]}}"); -// -//static std::string hardware_opt("{\"paper\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u7eb8\\u5f20\\u5c3a\\u5bf8\",\"desc\":\"\\u8bbe\\u7f6e\\u51fa\\u56fe\\u5927\\u5c0f\",\"type\":\"string\",\"cur\":\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"default\":\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"size\":48,\"range\":[\"A3\",\"8\\u5f00\",\"A4\",\"A4\\u6a2a\\u5411\",\"16\\u5f00\",\"16\\u5f00\\u6a2a\\u5411\",\"A5\",\"A5\\u6a2a\\u5411\",\"A6\",\"A6\\u6a2a\\u5411\",\"B4\",\"B5\",\"B5\\u6a2a\\u5411\",\"B6\",\"B6\\u6a2a\\u5411\",\"Letter\",\"Letter\\u6a2a\\u5411\",\"Double Letter\",\"LEGAL\",\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"\\u4e09\\u8054\\u8bd5\\u5377\"]},\"is-size-check\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u5c3a\\u5bf8\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u7eb8\\u5f20\\u5b9e\\u9645\\u5c3a\\u5bf8\\u4e0e\\u8bbe\\u7f6e\\u662f\\u5426\\u5339\\u914d\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"paper==A3\",\"==A4\",\"==A4\\u6a2a\\u5411\",\"==A5\",\"==A5\\u6a2a\\u5411\",\"==A6\",\"==A6\\u6a2a\\u5411\",\"==B4\",\"==B5\",\"==B5\\u6a2a\\u5411\",\"==B6\",\"==B6\\u6a2a\\u5411\",\"==Double Letter\",\"==LEGAL\",\"==Letter\",\"==Letter\\u6a2a\\u5411\"]},\"resolution\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u8bbe\\u7f6e\\u626b\\u63cf\\u56fe\\u50cf\\u7684\\u5206\\u8fa8\\u7387\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":{\"min\":100,\"max\":600,\"step\":1}},\"image-quality\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u753b\\u8d28\",\"desc\":\"\\u9009\\u62e9\\u626b\\u63cf\\u4eea\\u7684\\u753b\\u8d28\\u6a21\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u901f\\u5ea6\\u4f18\\u5148\",\"default\":\"\\u901f\\u5ea6\\u4f18\\u5148\",\"size\":24,\"range\":[\"\\u901f\\u5ea6\\u4f18\\u5148\",\"\\u753b\\u8d28\\u4f18\\u5148\"],\"depend_or\":[\"resolution>=300\"]},\"is-wait-scan\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u5f85\\u7eb8\\u626b\\u63cf\",\"desc\":\"\\u542f\\u7528\\u540e��\\u6587\\u7a3f\\u653e\\u5165\\u626b\\u63cf\\u4eea\\u65f6\\u5c06\\u81ea\\u52a8\\u542f\\u52a8\\u626b\\u63cf\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"scan-mode\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u626b\\u63cf\\u5f20\\u6570\",\"desc\":\"\\u9009\\u62e9\\u6307\\u5b9a\\u6570\\u91cf\\u626b\\u63cf\\u6216\\u8fde\\u7eed\\u626b\\u63cf\",\"type\":\"string\",\"cur\":\"\\u8fde\\u7eed\\u626b\\u63cf\",\"default\":\"\\u8fde\\u7eed\\u626b\\u63cf\",\"size\":32,\"range\":[\"\\u8fde\\u7eed\\u626b\\u63cf\",\"\\u626b\\u63cf\\u6307\\u5b9a\\u5f20\\u6570\"],\"depend_or\":[\"is-wait-scan==false\"]},\"scan-count\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u626b\\u63cf\\u6570\\u91cf\",\"desc\":\"\\u626b\\u63cf\\u6307\\u5b9a\\u6570\\u91cf\",\"type\":\"int\",\"cur\":1,\"default\":1,\"size\":4,\"depend_or\":[\"scan-mode==\\u626b\\u63cf\\u6307\\u5b9a\\u5f20\\u6570\"]},\"is-ultrosonic\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8d85\\u58f0\\u6ce2\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u662f\\u5426\\u51fa\\u73b0\\u53cc\\u5f20\\u9001\\u5165\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"double-feed\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u53cc\\u5f20\\u56fe\\u7247\\u5904\\u7406\",\"desc\":\"\\u68c0\\u6d4b\\u5230\\u53cc\\u5f20\\u8fdb\\u7eb8\\u540e\\u7684\\u5904\\u7406\\u65b9\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u4e22\\u5f03\\u56fe\\u50cf\\u5e76\\u505c\\u6b62\\u626b\\u63cf\",\"default\":\"\\u4e22\\u5f03\\u56fe\\u50cf\\u5e76\\u505c\\u6b62\\u626b\\u63cf\",\"size\":40,\"range\":[\"\\u4e22\\u5f03\\u56fe\\u50cf\\u5e76\\u505c\\u6b62\\u626b\\u63cf\",\"\\u4e0a\\u4f20\\u56fe\\u50cf\\u5e76\\u505c\\u6b62\\u626b\\u63cf\"],\"depend_or\":[\"is-ultrosonic==true\"]},\"is-staple\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u88c5\\u8ba2\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u662f\\u5426\\u51fa\\u73b0\\u7c98\\u8fde\\u9001\\u5165\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"is-check-askew\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u6b6a\\u659c\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u662f\\u5426\\u51fa\\u73b0\\u6b6a\\u659c\\u9001\\u5165\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"askew-range\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u6b6a\\u659c\\u5bb9\\u5fcd\\u5ea6\",\"desc\":\"\\u503c\\u8d8a\\u5c0f��\\u80fd\\u5bb9\\u5fcd\\u5f97\\u9001\\u5165\\u6587\\u7a3f\\u6b6a\\u659c\\u89d2\\u5ea6\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":3,\"default\":3,\"size\":4,\"range\":{\"min\":1,\"max\":5,\"step\":1},\"depend_or\":[\"is-check-askew==true\"]},\"is-check-dog-ear\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u6298\\u89d2\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u6587\\u7a3f\\u662f\\u5426\\u5b58\\u5728\\u6298\\u89d2\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"dog-ear-size\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u6298\\u89d2\\u5927\\u5c0f\",\"desc\":\"\\u503c\\u8d8a\\u5c0f��\\u80fd\\u68c0\\u6d4b\\u5230\\u7684\\u6298\\u89d2\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":70,\"default\":70,\"size\":4,\"range\":{\"min\":0,\"max\":100,\"step\":1},\"depend_or\":[\"is-check-dog-ear==true\"]},\"feed-strength\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u5206\\u7eb8\\u5f3a\\u5ea6\",\"desc\":\"\\u8bbe\\u7f6e\\u626b\\u63cf\\u4eea\\u7684\\u5206\\u7eb8\\u529b\\u5ea6\",\"type\":\"string\",\"cur\":\"\\u5f31\",\"default\":\"\\u5f31\",\"size\":16,\"range\":[\"\\u5f31\",\"\\u4e00\\u822c\",\"\\u5f3a\"]},\"time-to-sleep\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u4f11\\u7720\\u65f6\\u95f4\",\"desc\":\"\\u8bbe\\u7f6e\\u626b\\u63cf\\u4eea\\u7684\\u4f11\\u7720\\u65f6\\u95f4\",\"type\":\"string\",\"cur\":\"\\u4e0d\\u4f11\\u7720\",\"default\":\"\\u4e0d\\u4f11\\u7720\",\"size\":24,\"range\":[\"\\u4e0d\\u4f11\\u7720\",\"\\u4e94\\u5206\\u949f\",\"\\u5341\\u5206\\u949f\",\"\\u534a\\u5c0f\\u65f6\",\"\\u4e00\\u5c0f\\u65f6\",\"\\u4e24\\u5c0f\\u65f6\",\"\\u56db\\u5c0f\\u65f6\"]},\"is-auto-strength\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u81ea\\u52a8\\u5206\\u7eb8\\u5f3a\\u5ea6\",\"desc\":\"\\u626b\\u63cf\\u4eea\\u81ea\\u52a8\\u4fee\\u6b63\\u5206\\u7eb8\\u529b\\u5ea6\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"feed-strength-value\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"group\":\"feeder\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\" \\u8fdb\\u7eb8\\u5931\\u8d25\\u7387\",\"desc\":\"\\u9ad8\\u4e8e\\u8be5\\u503c\\u65f6\\u626b\\u63cf\\u4eea\\u5c06\\u8c03\\u6574\\u5206\\u7eb8\\u529b\\u5ea6\",\"type\":\"float\",\"cur\":0.100000,\"default\":0.100000,\"size\":4,\"range\":{\"min\":0.100000,\"max\":0.900000,\"step\":0.080000},\"depend_or\":[\"is-auto-strength==true\"]}}"); - -class readonly_cfg : public sane_cfg_provider -{ - json* jsn_; - - std::string get_ip(void) - { - std::string val(sys_util::get_command_output("ifconfig | grep broadcast")); - char buf[40] = { 0 }; - - if (sscanf(val.c_str(), " inet %s", buf)) - val = buf; - - return std::move(val); - } - std::string get_mac(void) - { - std::string val(sys_util::get_command_output("ifconfig | grep ether")); - char buf[40] = { 0 }; - - if (sscanf(val.c_str(), " ether %s", buf)) - val = buf; - - return std::move(val); - } - -public: - readonly_cfg() : jsn_(nullptr) - { - jsn_ = new json(); - jsn_->attach_text((char*)"{\"dev-sn\":{\"category\":\"base\",\"readonly\":true,\"affect\":0,\"group\":\"\\u8BBE\\u5907\\u5C5E\\u6027\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8bbe\\u5907\\u5e8f\\u5217\\u53f7\",\"desc\":\"\\u8bbe\\u5907\\u552f\\u4e00\\u7f16\\u7801\",\"type\":\"string\",\"cur\":\"G100S20230001\",\"size\":20,\"ver\":1},\"fmw-ver\":{\"category\":\"base\",\"readonly\":true,\"affect\":0,\"group\":\"\\u8BBE\\u5907\\u5C5E\\u6027\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u56fa\\u4ef6\\u7248\\u672c\\u53f7\",\"desc\":\"\\u8bbe\\u5907\\u9a71\\u52a8\\u7248\\u672c\\u53f7\",\"type\":\"string\",\"cur\":\"FMWV1001\",\"size\":10,\"ver\":1},\"ip-addr\":{\"category\":\"base\",\"readonly\":true,\"affect\":0,\"group\":\"\\u8BBE\\u5907\\u5C5E\\u6027\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8bbe\\u5907IP\\u5730\\u5740\",\"desc\":\"\\u5f53\\u8bbe\\u5907\\u8fde\\u63a5\\u7f51\\u7edc\\u65f6\\u5206\\u914d\\u7684IP\\u5730\\u5740\",\"type\":\"string\",\"cur\":\"0.0.0.0\",\"size\":60,\"ver\":1},\"mac-addr\":{\"category\":\"base\",\"readonly\":true,\"affect\":0,\"group\":\"\\u8BBE\\u5907\\u5C5E\\u6027\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u8bbe\\u5907MAC\\u5730\\u5740\",\"desc\":\"\\u8bbe\\u5907MAC\\u5730\\u5740\",\"type\":\"string\",\"cur\":\"00:11:22:33:44:55\",\"size\":30,\"ver\":1}}"); - } - - -protected: - ~readonly_cfg() - { - jsn_->release(); - } - -public: - virtual int32_t get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) override - { - if (!len) - return EINVAL; - - std::string val(""), str(""); - - if (cfg_name) - { - if (strcmp(cfg_name, "ip-addr") == 0) - str = val = get_ip(); - else if (strcmp(cfg_name, "mac-addr") == 0) - str = val = get_mac(); - else - { - json* child = nullptr; - if (jsn_->get_value(cfg_name, child) && child) - { - val = sane_cfg_provider::sane_option_value_get(child, "cur", &str); - - child->release(); - } - } - } - else - { - std::string cur(get_ip()); - if (!cur.empty()) - { - json* child = nullptr; - if (jsn_->get_value("ip-addr", child) && child) - { - child->set_value("cur", cur.c_str()); - child->release(); - } - } - - cur = get_mac(); - if (!cur.empty()) - { - json* child = nullptr; - if (jsn_->get_value("mac-addr", child) && child) - { - child->set_value("cur", cur.c_str()); - child->release(); - } - } - - val = jsn_->to_string(); - log_cls::log(LOG_LEVEL_ALL, "readonly config json: %s\n", val.c_str()); - } - - if (val.empty()) - return ENOENT; - - if(strval) - *strval = std::move(str); - - if (*len < val.length()) - { - *len = val.length() + 4; - return ENOMEM; - } - else - { - memcpy(buf, val.c_str(), val.length()); - *len = val.length(); - - return 0; - } - } - virtual int32_t set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) override - { - // read-only attributes not support this operation !!! - return EINVAL; - } -}; - -class image_packet : public data_source -{ - MemoryPtr img_; - dyn_mem_ptr head_; - uint32_t offset_; - uint32_t ind_; - uint64_t cur_mem_; - -public: - image_packet(MemoryPtr img, uint32_t cnt, uint32_t scanid, uint64_t total_mem) : img_(img), offset_(0), ind_(cnt), cur_mem_(total_mem) - { - LPPACK_BASE pack = nullptr; - LPPACKIMAGE pimg = nullptr; - - head_ = dyn_mem::memory(sizeof(PACK_BASE) + sizeof(PACKIMAGE)); - pack = (LPPACK_BASE)head_->ptr(); - pimg = (LPPACKIMAGE)pack->payload; - BASE_PACKET_REPLY(*pack, PACK_CMD_SCAN_IMG_ROGER, scanid, 0); - pack->payload_len = sizeof(PACKIMAGE); - - pimg->pos.new_img = 1; - pimg->pos.img_over = 1; - pimg->pos.paper_ind = cnt; - pimg->data_size = img->size(); - pimg->info_size = 0; - - head_->set_len(sizeof(PACK_BASE) + sizeof(PACKIMAGE)); - log_cls::log(LOG_LEVEL_ALL, "Image-%04u wait to be sent: size = %u, memory usage %s\n", ind_, img->size(), sys_util::format_readable_bytes(cur_mem_).c_str()); - } - -protected: - virtual ~image_packet() - { - uint32_t size = img_->size(); - - head_->release(); - img_.reset(); - log_cls::log(LOG_LEVEL_ALL, "Image-%04u sending complete: %u/%u, memory usage %s\n", ind_, offset_, size, sys_util::format_readable_bytes(sys_util::get_memory_usage("scan")).c_str()); - } - -public: - virtual bool is_memory_block(void) override - { - return false; - } - virtual uint32_t get_rest(void) override - { - return head_->get_rest() + img_->size() - offset_; - } - - // following API valid when is_memory_block() return true - virtual uint8_t* ptr(void) override - { - return nullptr; - } - - // following API valid when is_memory_block() return false. return error code - virtual int fetch_data(void* buf, uint32_t* size) override - { - if(head_->get_rest()) - { - if(*size < head_->get_rest()) - { - memcpy(buf, head_->ptr(), *size); - } - else - { - memcpy(buf, head_->ptr(), head_->get_rest()); - *size = head_->get_rest(); - } - head_->used(*size); - } - else - { - if(*size + offset_ >= img_->size()) - { - memcpy(buf, img_->data() + offset_, img_->size() - offset_); - *size = img_->size() - offset_; - offset_ = img_->size(); - } - else - { - memcpy(buf, img_->data() + offset_, *size); - offset_ += *size; - } - } - - return 0; - } -}; - -void dump_buf(uint8_t *data, int len) -{ - uint32_t addr = 0; - std::string cont(""), asc(""); - char buf[20] = { 0 }; - for(int i = 0; i < len; ++i) - { - if((i % 16) == 0) - { - if (cont.length()) - log_cls::log(LOG_LEVEL_ALL, "%s %s\n", cont.c_str(), asc.c_str()); - sprintf(buf, "0x%08x ", addr); - addr += 16; - cont = buf; - asc = ""; - } - else if((i % 8) == 0) - { - cont += " "; - } - - uint8_t v = data[i]; - sprintf(buf, "%02X ", v); - cont += buf; - if(v >= 0x20 && v < 0x7f) - asc.append(1, v); - else - asc += "."; - } - if(asc.length()) - { - std::string pad(" "); - if(asc.length() <= 8) - pad.erase((16 - asc.length()) * 3 + 2); - else if(asc.length() < 16) - pad.erase((16 - asc.length()) * 3); - else - pad = ""; - log_cls::log(LOG_LEVEL_ALL, "%s%s %s\n", cont.c_str(), pad.c_str(), asc.c_str()); - } -} -std::string load_mini_file(const char* path) -{ - FILE* src = fopen(path, "rb"); - std::string cont(""); - - if(src) - { - int len = 0; - - fseek(src, 0, SEEK_END); - len = ftell(src); - cont.resize(len); - fseek(src, 0, SEEK_SET); - fread(&cont[0], 1, len, src); - fclose(src); - } - - return cont; -} - -dyn_mem_ptr UsbDevice::unhandled_ep0(struct usb_functionfs_event* pev) -{ - return nullptr; -} -dyn_mem_ptr UsbDevice::handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) -{ - dyn_mem_ptr reply = nullptr; - LPPACK_BASE pk = nullptr; - size_t base_head_size = sizeof(PACK_BASE); - - if(pack->size != base_head_size) - { - log_cls::log(LOG_LEVEL_ALL, "Unknown Packet with %d bytes:\n", *used); - dump_buf((uint8_t*)pack, *used); - reply = dyn_mem::memory(base_head_size); - LPPACK_BASE p = (LPPACK_BASE)reply->ptr(); - BASE_PACKET_REPLY(*p, PACK_CMD_INVALID, pack->pack_id, pack->cmd); - reply->set_len(base_head_size); - - return reply; - } - - switch(pack->cmd) - { - case PACK_CMD_SYNC: - *used = sizeof(PACK_BASE); - reply = dyn_mem::memory(base_head_size); - pk = (LPPACK_BASE)reply->ptr(); - BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, 0); - reply->set_len(base_head_size); - break; - case PACK_CMD_SETTING_GET_CUR: - if(*used < base_head_size + pack->payload_len) - *used = 0; - else - { - std::string val(""), str(""); - uint32_t err = cfg_->get_config(val, pack->payload, &str); - LPCFGVAL cfg = nullptr; - - if (val.empty()) - val = "No value found."; - log_cls::log(LOG_LEVEL_ALL, "Option '%s' value: %s\n", pack->payload, str.c_str()); - reply = dyn_mem::memory(base_head_size + sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1); - pk = (LPPACK_BASE)reply->ptr(); - BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err); - cfg = (LPCFGVAL)pk->payload; - cfg->val_size = val.length(); - cfg->val_off = 0; - cfg->name_off = val.length() + 1; - pk->payload_len = sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1; - memcpy(cfg->data, val.c_str(), val.length()); - strcpy(cfg->data + cfg->name_off, pack->payload); - reply->set_len(base_head_size + pk->payload_len); - *used = base_head_size + pack->payload_len; - } - break; - case PACK_CMD_SETTING_GET: - *used = base_head_size; - { - std::string val(""); - uint32_t err = cfg_->get_config(val); - - reply = dyn_mem::memory(base_head_size + val.length() + 1); - pk = (LPPACK_BASE)reply->ptr(); - BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err); - strcpy(pk->payload, val.c_str()); - pk->payload_len = val.length() + 1; - reply->set_len(base_head_size + val.length() + 1); - } - break; - case PACK_CMD_SETTING_SET: - if (*used < base_head_size + pack->payload_len) - *used = 0; - else - { - LPCFGVAL cfg = (LPCFGVAL)pack->payload, - cfg_ret = nullptr; - std::string name(cfg->data + cfg->name_off); - size_t l = base_head_size + sizeof(CFGVAL) + name.length() + 1 + cfg->max_size + 1, val_size = cfg->val_size; - int32_t err = 0; - uint32_t after = 0; - - reply = dyn_mem::memory(l); - pk = (LPPACK_BASE)reply->ptr(); - cfg_ret = (LPCFGVAL)pk->payload; - cfg_ret->name_off = 0; - strcpy(cfg_ret->data + cfg_ret->name_off, name.c_str()); - cfg_ret->val_off = name.length() + 1; - memcpy(cfg_ret->data + cfg_ret->val_off, cfg->data + cfg->val_off, cfg->val_size); - cfg_ret->val_size = cfg->val_size; - cfg_ret->max_size = cfg->max_size; - cfg_ret->type = cfg->type; - err = cfg_->set_config(cfg->data + cfg->name_off, cfg_ret->data + cfg_ret->val_off, &val_size, &after); - cfg_ret->after_do = after; - cfg_ret->val_size = val_size; - BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err); - pk->payload_len = sizeof(CFGVAL) + name.length() + 1 + cfg->max_size + 1; - reply->set_len(l); - } - break; - case PACK_CMD_FILE_WRITE_REQ: - if(*used < pack->payload_len + pack->size) - { - *used = 0; - } - else - { - LPTXFILE pfi = (LPTXFILE)pack->payload; - std::string path(pfi->path); - int err = 0; - file_saver *saver = new file_saver(); - - err = saver->open(path.c_str(), pfi->size); - reply = dyn_mem::memory(base_head_size); - reply->set_len(base_head_size); - BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); - *used = base_head_size + pack->payload_len; - if(err) - { - saver->release(); - saver = nullptr; - } - else - { - saver->set_packet_param(pack->cmd, pack->pack_id); - } - log_cls::log(LOG_LEVEL_DEBUG, "receive file (%u bytes): %s = %d\n", pfi->size, path.c_str(), err); - *required = dynamic_cast(saver); - } - break; - case PACK_CMD_FILE_READ_REQ: - if(*used < pack->payload_len + pack->size) - { - *used = 0; - } - else - { - LPTXFILE pfi = (LPTXFILE)pack->payload; - std::string path(pfi->path); - int err = 0; - file_reader *reader = new file_reader(); - - err = reader->open(path.c_str()); - reply = dyn_mem::memory(base_head_size + sizeof(TXFILE)); - reply->set_len(base_head_size + sizeof(TXFILE)); - BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); - *used = base_head_size + pack->payload_len; - log_cls::log(LOG_LEVEL_DEBUG, "To send file '%s' with %u bytes = %d\n", path.c_str(), reader->get_rest(), err); - if(err) - { - reader->release(); - reader = nullptr; - } - else - { - ((LPPACK_BASE)reply->ptr())->payload_len = sizeof(TXFILE); - ((LPTXFILE)((LPPACK_BASE)reply->ptr())->payload)->size = reader->get_rest(); - reader->set_packet_param(pack->cmd, pack->pack_id); - } - *required = dynamic_cast(reader); - } - break; - case PACK_CMD_SCAN_START: - { - int err = 0; - img_cnt_ = 0; - scan_id_ = pack->pack_id; - scan_err_ = 0; - if(scan_over_pack_) - { - scan_over_pack_->release(); - scan_over_pack_ = nullptr; - } - - { - ctrl_handler(-1, (usb_ctrlrequest*)SR_IM_CLEAR, (unsigned char*)0); - log_cls::log(LOG_LEVEL_ALL, "Memory usage before starting to scan: %s\n", sys_util::format_readable_bytes(sys_util::get_memory_usage("scan")).c_str()); - bool ret = ctrl_handler(-1, (usb_ctrlrequest*)15, (unsigned char*)0x160); // hardware configuration - - ctrl_handler(-1, (usb_ctrlrequest*)SR_SCAN_CNT, (unsigned char*)scan_cnt_); - ctrl_handler(-1, (usb_ctrlrequest*)SR_SCAN_DPI, (unsigned char*)dpi_); - ctrl_handler(-1, (usb_ctrlrequest*)SR_CONFIF_IMGPROCPARAM, (unsigned char*)0); - log_cls::log(LOG_LEVEL_ALL, "Start scanning %d papers and %d DPI ...\n", scan_cnt_, dpi_); - ret = ctrl_handler(-1, nullptr, nullptr); - log_cls::log(LOG_LEVEL_ALL, "Start scanning %s\n", ret ? "OK" : "Failed"); - log_cls::log(LOG_LEVEL_ALL, "Memory usage after scanning started: %s\n", sys_util::format_readable_bytes(sys_util::get_memory_usage("scan")).c_str()); - } - - reply = dyn_mem::memory(base_head_size); - reply->set_len(base_head_size); - BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); - *used = base_head_size; - } - break; - case PACK_CMD_SCAN_STOP: - { - int err = 0; - - log_cls::log(LOG_LEVEL_ALL, "Received command Stop-Scan.\n"); - ctrl_handler(-1, nullptr, (unsigned char*)1); - reply = dyn_mem::memory(base_head_size); - reply->set_len(base_head_size); - BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); - *used = base_head_size; - } - break; - default: - log_cls::log(LOG_LEVEL_ALL, "Unhandled Packet with command %d:\n", pack->cmd); - dump_buf((uint8_t*)pack, *used); - reply = dyn_mem::memory(base_head_size); - LPPACK_BASE p = (LPPACK_BASE)reply->ptr(); - BASE_PACKET_REPLY(*p, pack->cmd + 1, pack->pack_id, EINVAL); - reply->set_len(base_head_size); - break; - } - - return reply; -} void UsbDevice::do_system_command(const char* cmd) { log_cls::log(LOG_LEVEL_ALL, "invoking system command: %s ...\n", cmd); get_system_output(cmd); log_cls::log(LOG_LEVEL_ALL, "invoked system command: %s.\n", cmd); } -void UsbDevice::init(void) + +#include "commondef.h" +int UsbDevice::start_scan(void) { - readonly_cfg* r = new readonly_cfg(); - hardware *hrd = new hardware(); + ctrl_handler(-1, (usb_ctrlrequest*)SR_IM_CLEAR, (unsigned char*)0); + ctrl_handler(-1, (usb_ctrlrequest*)SR_CONFIF_IMGPROCPARAM, (unsigned char*)0); - size_t l = sizeof(dpi_); - - cfg_text_ = "{\"resolution\":{\"category\":\"base\",\"readonly\":false,\"affect\":2,\"ver\":1,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u8bbe\\u7f6e\\u626b\\u63cf\\u56fe\\u50cf\\u7684\\u5206\\u8fa8\\u7387\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":[100,150,200,300,600]},\"count\":{\"category\":\"base\",\"readonly\":false,\"affect\":0,\"ver\":1,\"group\":\"base\",\"visible\":true,\"field\":\"Common\",\"pos\":0,\"unit\":\"None\",\"title\":\"\\u626b\\u63cf\\u5f20\\u6570\",\"desc\":\"\\u8bbe\\u7f6e\\u626b\\u63cf\\u7684\\u7eb8\\u5f20\\u6570\\u91cf\",\"type\":\"int\",\"cur\":-1,\"default\":-1,\"size\":4,\"range\":[-1,1]}}"; - l = get_config(&dpi_, &l, "resolution"); - l = sizeof(scan_cnt_); - l = get_config(&scan_cnt_, &l, "count"); - cfg_ = new sane_cfg_mgr(); - cfg_->reg_sane_provider(dynamic_cast(r)); - l = cfg_->reg_sane_provider(dynamic_cast(this)); - l = cfg_->reg_sane_provider(dynamic_cast(hrd)); - hrd->release(); - r->release(); + return ctrl_handler(-1, nullptr, nullptr) ? 0 : EBADF; } -void UsbDevice::save_image(MemoryPtr data, bool img) +int UsbDevice::stop_scan(void) { - static uint64_t max_mem = 0; + return ctrl_handler(-1, nullptr, (unsigned char*)1) ? 0 : EBADF; +} +int UsbDevice::set_dpi(int *dpix, int* dpiy) +{ + int dpi = 0; - if(img) + if(dpix) { - uint64_t n = sys_util::get_memory_usage("scan"); - uint32_t que = 0; - image_packet *ip = new image_packet(data, ++img_cnt_, scan_id_, n); - - if(max_mem < n) - max_mem = n; - - que = usb_->write_bulk(ip); - ip->release(); - - // check has completed ? - if(scan_over_pack_) - { - ctrl_handler(-2, (usb_ctrlrequest*)SR_GET_IMAGEPROCESSDONE, (unsigned char*)&n); - if(n) - { - usb_->write_bulk(scan_over_pack_); - scan_over_pack_->release(); - scan_over_pack_ = nullptr; - } - } - } - else if(data) - { - HGIntInfo* info = (HGIntInfo*)data->data(); - dyn_mem_ptr reply = dyn_mem::memory(sizeof(PACK_BASE)); - int cmd = /*PACK_CMD_SCAN_FINISHED_ROGER*/0, - err = 0; - - if(info->From != HGType::MBEvent || scan_id_ == 0) - log_cls::log(LOG_LEVEL_ALL, "Scanner event: From = %d, Code = %d, Img_Index = %d\n", info->From, info->Code, info->Img_Index); - - if(info->From == HGType::MtBoard) - { - cmd = PACK_CMD_SCAN_FINISHED_ROGER; - switch(info->Code) - { - case 2: - err = SCANNER_STATUS_NO_PAPER; - break; - case 4: - err = SCANNER_STATUS_COVER_OPENNED; - break; - case 8: - err = SCANNER_STATUS_FEED_FAILED; - break; - case 0x10: - err = SCANNER_STATUS_PAPER_JAMMED; - break; - case 0x20: - err = SCANNER_STATUS_DOUBLE_FEEDED; - break; - case 0x40: - err = SCANNER_STATUS_STAPLE_ON; - break; - case 0x80: - err = SCANNER_STATUS_PAPER_ASKEW; - break; - case 0x20000: - break; - } - } - else if(info->From == HGType::IMG) - { - if(info->Code == 1) - { - err = SCANNER_STATUS_DOGEAR; - cmd = PACK_CMD_SCAN_FINISHED_ROGER; - } - else if(info->Code == 2) - { - err = SCANNER_STATUS_SIZE_ERR; - cmd = PACK_CMD_SCAN_FINISHED_ROGER; - } - } - else if(info->From == HGType::V4L2 || info->From == HGType::STOPSCAN) - { - cmd = PACK_CMD_SCAN_FINISHED_ROGER; - } - - if(scan_id_ == 0 && info->From == HGType::MBEvent) - { - BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), PACK_CMD_STATUS_ROGER, 0, info->Code); - reply->set_len(sizeof(PACK_BASE)); - usb_->write_bulk(reply); - } + if(*dpix < 300) + *dpix = 200; + else if(*dpix < 500) + *dpix = 300; else - { - if(err && scan_err_ == 0) - scan_err_ = err; - if(scan_id_ && /*cmd == PACK_CMD_SCAN_FINISHED_ROGER*/info->From == HGType::STOPSCAN && scan_over_pack_ == nullptr) - { - char ebuf[20] = {0}; - - err = scan_err_; - log_cls::log(LOG_LEVEL_ALL, "Scan over with error: %s; Max memory usage: %s\n", log_cls::str_scanner_status((scanner_status)scan_err_, ebuf), sys_util::format_readable_bytes(max_mem).c_str()); - max_mem = 0; - BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), cmd, scan_id_, err); - reply->set_len(sizeof(PACK_BASE)); - scan_id_ = 0; - - // check if the image-proc-queue has completed ... - // ctrl_handler(-2, (usb_ctrlrequest*)SR_GET_IMAGEPROCESSDONE, (unsigned char*)&err); - err = 1; - if(err) - usb_->write_bulk(reply); - else - { - scan_over_pack_ = reply; - scan_over_pack_->add_ref(); - } - } - } - reply->release(); + *dpix = 600; + dpi = *dpix; } - else + if(dpiy) { - // paper count ... - dyn_mem_ptr reply = dyn_mem::memory(sizeof(PACK_BASE)); - BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), PACK_CMD_SCAN_PAPER_ROGER, 0, 0); - reply->set_len(sizeof(PACK_BASE)); - usb_->write_bulk(reply); - reply->release(); - } -} - -int32_t UsbDevice::get_config(void* buf, size_t* len, const char* cfg_name, std::string* strval) -{ - int32_t ret = EINVAL; - - if(!len) - return ret; - - if(cfg_name) - { - json *jsn = new json(); - if(jsn->attach_text(&cfg_text_[0])) - { - ret = inner_get_config(jsn, buf, len, cfg_name, strval); - // json* child = nullptr; - - // ret = ENOENT; - // if(jsn->get_value(cfg_name, child) && child) - // { - // std::string val(sane_cfg_provider::sane_option_value_get(child, "cur", strval)); - // child->release(); - - // if(*len < val.length()) - // { - // *len = val.length(); - // ret = ENOMEM; - // } - // else - // { - // memcpy(buf, val.c_str(), val.length()); - // *len = val.length(); - // } - // } - jsn->release(); - } - } - else - { - if(*len < cfg_text_.length() + 1) - { - *len = cfg_text_.length() + 4; - ret = ENOMEM; - } + if(*dpiy < 300) + *dpiy = 200; + else if(*dpiy < 500) + *dpiy = 300; else - { - strcpy((char*)buf, cfg_text_.c_str()); - *len = cfg_text_.length(); - ret = 0; - } - } + *dpiy = 600; - return ret; + if(dpi == 0) + dpi = *dpiy; + } + if(dpi == 0) + dpi = 200; + + return ctrl_handler(-1, (usb_ctrlrequest*)SR_SCAN_DPI, (unsigned char*)dpi) ? 0 : EBADF; } -int32_t UsbDevice::set_config(const char* cfg_name, void* data, size_t* len, uint32_t* afterdo) +int UsbDevice::set_scan_num(int num) { - json *jsn = new json(); - int32_t ret = EINVAL; - - if(jsn->attach_text(&cfg_text_[0])) - { - json* child = nullptr; - - ret = ENOENT; - if(jsn->get_value(cfg_name, child) && child) - { - int val = 0; - child->get_value("affect", val); - if(afterdo) - *afterdo = val; - - if(strcmp(cfg_name, "resolution") == 0) - { - child->get_value("cur", val); - ret = EUCLEAN; - val = *(int*)data; - if(val == 100 || val == 150 || val == 200 || val == 300 || val == 600) - ret = 0; - else if(val < 125) - val = 100; - else if(val < 175) - val = 150; - else if(val < 250) - val = 200; - else if(val < 450) - val = 300; - else - val = 600; - *(int*)data = val; - child->set_value("cur", val); - dpi_ = val; - log_cls::log(LOG_LEVEL_ALL, "Set %s to %d\n", cfg_name, dpi_); - cfg_text_ = jsn->to_string(); - } - else if(strcmp(cfg_name, "count") == 0) - { - child->get_value("cur", val); - ret = EUCLEAN; - val = *(int*)data; - if(val == -1 || val == 1) - ret = 0; - else - val = -1; - *(int*)data = val; - child->set_value("cur", val); - scan_cnt_ = val; - log_cls::log(LOG_LEVEL_ALL, "Set %s to %d\n", cfg_name, scan_cnt_); - cfg_text_ = jsn->to_string(); - } - child->release(); - } - jsn->release(); - } - - return ret; + return ctrl_handler(-1, (usb_ctrlrequest*)SR_SCAN_CNT, (unsigned char*)num) ? 0 : EBADF; } +int UsbDevice::set_img_receiver(void* api, void* param) +{ + uint64_t cb[] = {(uint64_t)api, (uint64_t)param}; + return ctrl_handler(-1, (usb_ctrlrequest*)-1, (unsigned char*)cb) ? 0 : EBADF; +} #endif diff --git a/device/gxx-linux/usb/usbimageprocqueue.h b/device/gxx-linux/usb/usbimageprocqueue.h index 8f4d852..de22c50 100644 --- a/device/gxx-linux/usb/usbimageprocqueue.h +++ b/device/gxx-linux/usb/usbimageprocqueue.h @@ -9,19 +9,76 @@ #include +#include "./src/async_model/common/packet.h" + class UsbImageProcQueue { void(*img_keeper_)(MemoryPtr, bool, void*); void* kp_param_; + int scan_status_; + int dpi_x_; + int dpi_y_; + + int sensor_status_2_scanner_status(int ss) + { + switch(ss) + { + case 2: + ss = SCANNER_STATUS_NO_PAPER; + break; + case 4: + ss = SCANNER_STATUS_COVER_OPENNED; + break; + case 8: + ss = SCANNER_STATUS_FEED_FAILED; + break; + case 0x10: + ss = SCANNER_STATUS_PAPER_JAMMED; + break; + case 0x20: + ss = SCANNER_STATUS_DOUBLE_FEEDED; + break; + case 0x40: + ss = SCANNER_STATUS_STAPLE_ON; + break; + case 0x80: + ss = SCANNER_STATUS_PAPER_ASKEW; + break; + case 0x20000: + break; + } + + return ss; + } public: - UsbImageProcQueue(NotifyPtr notify) : img_keeper_(nullptr), kp_param_(nullptr) + UsbImageProcQueue(NotifyPtr notify) : img_keeper_(nullptr), kp_param_(nullptr), scan_status_(0), dpi_x_(200), dpi_y_(200) { this->notify = notify; } - void push(MemoryPtr image,bool containsimg) + void push(MemoryPtr image,bool containsimg) { + if(!containsimg) + { + void (*push_image)(int data_type, void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel clr, img_status status, bool img_new, bool img_over, void* param) = nullptr; + HGIntInfo* info = (HGIntInfo*)image->data(); + + *(uint64_t*)&push_image = (uint64_t)img_keeper_; + if(info->From == HGType::STOPSCAN) + { + if(push_image) + push_image(IMG_CB_STOPPED, nullptr, sensor_status_2_scanner_status(info->Code), 0, dpi_x_, dpi_y_, 0, PAPER_SIDE_LEFT, (clr_channel)0, (img_status)0, true, true, kp_param_); + } + else + { + scan_status_ = sensor_status_2_scanner_status(info->Code); + if(push_image) + push_image(IMG_CB_STATUS, nullptr, sensor_status_2_scanner_status(info->Code), 0, dpi_x_, dpi_y_, 0, PAPER_SIDE_LEFT, (clr_channel)0, (img_status)0, true, true, kp_param_); + } + } + return; + if(img_keeper_) img_keeper_(image, containsimg, kp_param_); else @@ -45,12 +102,36 @@ public: } + bool push_raw(void *data, int width, int height = 0, int type = 0, int scannnum = 0, unsigned int fpgaversion = 0, int status = 0) + { + if(scannnum == 1) + scan_status_ = 0; + + void (*push_image)(int data_type, void* data, size_t w, size_t h, int dpi_x, int dpi_y, size_t paper_ind, paper_side side, clr_channel clr, img_status status, bool img_new, bool img_over, void* param) = nullptr; + + *(uint64_t*)&push_image = (uint64_t)img_keeper_; + if(push_image) + { + push_image(IMG_CB_IMAGE, data, width, height, dpi_x_, dpi_y_, scannnum, PAPER_SIDE_LEFT, (clr_channel)type, (img_status)status, true, true, kp_param_); + + return true; + } + + return false; + } void set_image_keeper(void(*img_keeper)(MemoryPtr, bool, void*), void* param) { + printf("UsbImageProcQueue::set_image_keeper(%p, %p)\n", img_keeper, param); + img_keeper_ = img_keeper; kp_param_ = param; } - + void set_dpi(int x, int y) + { + dpi_x_ = x; + dpi_y_ = y; + } + MemoryPtr front() { std::lock_guard lck(mx); diff --git a/device/gxx-linux/usb/usbnotify.cpp b/device/gxx-linux/usb/usbnotify.cpp index caf1095..58d0d14 100644 --- a/device/gxx-linux/usb/usbnotify.cpp +++ b/device/gxx-linux/usb/usbnotify.cpp @@ -48,7 +48,7 @@ void UsbNotify::run_notify() unsigned char buff[64]; while(brun) { - if (ae.wait(300000) && brun) + if (ae.wait(1000) && brun) { for(;;) { @@ -65,6 +65,7 @@ void UsbNotify::run_notify() usb->write_int(buff, sizeof(buff)); { + printf("\n notify msg "); std::lock_guard lck(mx); if(msgs.size()>0) msgs.pop(); diff --git a/device/gxx-linux/usb/usbreceive.cpp b/device/gxx-linux/usb/usbreceive.cpp index 4c453b0..142ab6f 100644 --- a/device/gxx-linux/usb/usbreceive.cpp +++ b/device/gxx-linux/usb/usbreceive.cpp @@ -37,7 +37,6 @@ int UsbReceive::read(MemoryPtr& memroy) int UsbReceive::read_bulk(void* data,unsigned int length) { - printf("(%p)perform read_bulk in UsbReceive object...\n", pthread_self()); int nread=0; if(usb.get()&&usb->is_connected()) { @@ -46,8 +45,6 @@ int UsbReceive::read_bulk(void* data,unsigned int length) else LOG_TRACE("read_bulk uncorrect data ptr or length"); } - printf("(%p)read_bulk in UsbReceive object OVER.\n", pthread_self()); - return nread; } diff --git a/device/gxx-linux/usb/usbservice.cpp b/device/gxx-linux/usb/usbservice.cpp index 97adaa0..dcbef6e 100644 --- a/device/gxx-linux/usb/usbservice.cpp +++ b/device/gxx-linux/usb/usbservice.cpp @@ -39,7 +39,6 @@ typedef struct static bool read_regs(unsigned int *regs, int regindex, int creg, std::shared_ptr ®sacess) { - printf("read_regs enter ...\n"); int index; for (int i = 0; i < creg; i++) { @@ -51,37 +50,31 @@ static bool read_regs(unsigned int *regs, int regindex, int creg, std::shared_pt } LOG_TRACE(string_format("read %d=%08x\n", index, regs[i])); } - printf("read_regs exit ...\n"); - return true; } static bool write_regs(unsigned int *regs, int regindex, int creg, std::shared_ptr ®sacess) { - printf("write_regs enter ...\n"); int index; - bool ret = true; for (int i = 0; i < creg; i++) { index = regindex + i; if (!regsacess->write(index, *(regs + i))) { LOG_ERROR(string_format("wirte error %d=%08x\n", index, regs[i])); - ret = false; - break; + return false; } LOG_TRACE(string_format("wirte %d=%08x\n", index, regs[i])); } - printf("write_regs exit.\n"); - return ret; + return true; } -UsbService::UsbService(std::shared_ptr fgparegs, std::shared_ptr motorregs, std::shared_ptr scannerregs) : devregs(scannerregs) +UsbService::UsbService(std::shared_ptr fgparegs, std::shared_ptr motorregs, std::shared_ptr scannerregs) { LOG_INIT(); this->fgparegs = fgparegs; this->motorregs = motorregs; - // this->devregs = scannerregs; + this->devregs = scannerregs; auto ctrl_handle = [&](int fd, struct usb_ctrlrequest *setup, unsigned char *buffer) -> bool { if(fd== -1) @@ -225,7 +218,6 @@ UsbService::UsbService(std::shared_ptr fgparegs, std::shared_ptrclear(); if (m_usbconnect) m_usbconnect(connected); @@ -237,15 +229,28 @@ UsbService::UsbService(std::shared_ptr fgparegs, std::shared_ptr UsbService::transmiter() { + // if(transmit.get()) + // { + // transmit.reset(); + // } + // transmit.reset(new UsbTransmit(usb)); + // return transmit; return transmit ? transmit : (transmit = std::shared_ptr(new UsbTransmit(usb))); } std::shared_ptr UsbService::receiver() { + // if(receiv.get()) + // { + // receiv.reset(); + // } + // receiv.reset(new UsbReceive(usb)); + // return receiv; return receiv ? receiv : (receiv = std::shared_ptr(new UsbReceive(usb))); } void UsbService::set_scannerregs(std::shared_ptr scannerregs) diff --git a/device/gxx-linux/usb/usbtransmit.cpp b/device/gxx-linux/usb/usbtransmit.cpp index 4456a4c..74a0d86 100644 --- a/device/gxx-linux/usb/usbtransmit.cpp +++ b/device/gxx-linux/usb/usbtransmit.cpp @@ -33,11 +33,12 @@ void UsbTransmit::write(MemoryPtr memroy) runthread.reset(new ThreadEx([this, memroy]() { if (usb && usb->is_connected()) { - LOG_TRACE("tx starting"); - LOG_TRACE(string_format("tx starting transfer index =%d mmy size = %d",++indextransfer,memroy->size())); + printf("tx starting"); + printf("tx starting transfer index =%d mmy size = %d",++indextransfer,memroy->size()); //printf("\n tx starting transfer index =%d mmy size = %d",++indextransfer,memroy->size()); int num= usb->write_bulk(memroy->data(), memroy->size()); - LOG_TRACE("tx end\n"); + printf("tx end\n"); + //printf("\n xfer size %d",num); } })); } diff --git a/device/gxx-linux/usb/vcxprj/usb.vcxproj b/device/gxx-linux/usb/vcxprj/usb.vcxproj index 1f716b4..c9a25cf 100644 --- a/device/gxx-linux/usb/vcxprj/usb.vcxproj +++ b/device/gxx-linux/usb/vcxprj/usb.vcxproj @@ -90,7 +90,7 @@ Level3 true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;_DEBUG;_CONSOLE;ASYNC_EP;%(PreprocessorDefinitions) true @@ -159,13 +159,18 @@ - + + + + + + @@ -179,12 +184,17 @@ - + + + + + + diff --git a/device/gxx-linux/usb/vcxprj/usb.vcxproj.filters b/device/gxx-linux/usb/vcxprj/usb.vcxproj.filters index d3c7359..2b22dcc 100644 --- a/device/gxx-linux/usb/vcxprj/usb.vcxproj.filters +++ b/device/gxx-linux/usb/vcxprj/usb.vcxproj.filters @@ -25,6 +25,12 @@ {d6e1c6f0-7ff7-47f1-8bdb-a9c43abbcd5a} + + {2f453e58-2ad0-46fd-9961-0f4d62736f6a} + + + {77373ea7-32be-462b-ba5a-6388294577ce} + @@ -102,15 +108,30 @@ src\common\json - - src\common\json - src\common src\common + + src\imgproc + + + src\imgproc + + + src\imgproc + + + src\imgproc + + + src\hdw + + + src\common\json + @@ -161,15 +182,30 @@ src\common\json - - src\common\json - src\common src\common + + src\imgproc + + + src\imgproc + + + src\imgproc + + + src\imgproc + + + src\hdw + + + src\common\json + diff --git a/device/gxx-linux/usb/xmake.lua b/device/gxx-linux/usb/xmake.lua index b487997..d912033 100644 --- a/device/gxx-linux/usb/xmake.lua +++ b/device/gxx-linux/usb/xmake.lua @@ -3,9 +3,10 @@ add_rules("mode.debug", "mode.release") target("gusb") set_kind("static") add_syslinks("pthread") - add_files("*.cpp", "src/*.cpp", "src/common/*.cpp", "src/common/json/*.c*", "src/hardware/*.cpp") + add_files("*.cpp", "src/*.cpp", "src/async_model/common/*.cpp", "src/async_model/common/json/*.c*", "src/async_model/hardware/*.cpp", "src/async_model/img_process/*.cpp", "src/async_model/img_process/algs/*.cpp" + , "src/async_model/io/*.c*", "src/async_model/scanner/*.c*") add_includedirs("inc") - add_includedirs("src/common") + add_includedirs("src/async_model") add_includedirs(".", { public = true}) add_packages("common") - add_deps("regs", "gimgproc", "applog") \ No newline at end of file + add_deps("regs", "gimgproc", "applog", "capimage") \ No newline at end of file diff --git a/device/gxx-linux/xmake.lua b/device/gxx-linux/xmake.lua index dd76911..963efdb 100644 --- a/device/gxx-linux/xmake.lua +++ b/device/gxx-linux/xmake.lua @@ -1,6 +1,5 @@ set_project("GXX") - option("device") set_showmenu(true) set_default("g100") @@ -64,13 +63,9 @@ target("conf") set_configdir("$(buildir)/config") add_configfiles("config.h.in", {prefixdir = "header"}) add_includedirs("$(buildir)/config/header", { public = true }) -target_end("conf") -includes("regs", "deviceio", "motor_run", "motorboard", "capimage", "usb", "service", "scanner", "imgproc", "applog","scanservice","fpgaupdate") - -add_includedirs("/usr/local/include/opencv4", "imgproc/ImageProcess") -add_linkdirs("/usr/local/lib/") +includes("regs", "deviceio", "motorboard", "capimage", "usb", "service", "scanner", "imgproc", "applog","scanservice","fpgaupdate","motorcontroller","display","testlcd","keymonitor","testkeymonitor","testdisplay","testwakeup") if has_config("testdemo") then - includes("testmotorboard", "testcapimage", "testusb", "testscanner", "testimgproc", "testregs") + includes("testmotorboard", "testcapimage", "testusb", "testscanner", "testimgproc", "testregs","testwakeup") end diff --git a/pc/code_twain/sln/usb_tools/Debug/usb_tools.exe b/pc/code_twain/sln/usb_tools/Debug/usb_tools.exe index 16c2333062baa973edf0f7060646f79e55c64cc6..c99fa54f156f8875ad982c60402430d3321cf04a 100644 GIT binary patch literal 1767936 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

vJX;jdp^jc_i}u=-KpN7r_i{)S*pDEJkU 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%0D)D5Of{vU~+vK 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 UiA5_xrQbNVe(o>_1|DNYgBwx+>SDxbO8@w zOPy2$&(2|Xh-Z)V7}%`yc~8F>R^Bs$yoOcM=99w@^GSpZ&id;%6?k=3_BJf@jv*Rq zMALlO_D$aDckz@8S<=qslWaqwB5=+G`PhKNO@AFGo4x6gwbziXy?x=@8STA)`1VA# zjst9N-k)>^2k;N`HOck>wafm3Y zcS~+CeD6yCpz>yE!uJC*sboW zn5(G0zNKoqc7-(;ee1Ik@1IfwlEpk%Y_5Pvecb7CkF#7|_ClovoQ80XJ8k2TRB7d& z?{f3W4R@^nr&&5SLdI_W*IMWBnSS1j;ul^2AMyJyK>dQ63>OC^j;BXlkb+8_7^-FVAsvi$pIQ+|JyS9KTG@Df=I6E(Op2oy^XtqgczlL zB-CFL%^wHub7#BwW*-F?QDQexFdY3sVBRb#>;%1c@OgXYb#-OoH{ZCY9l|t2jwNr zC-a$MKugkmI59GKr}^+6g)q$FRx9&uPsu9m2uGi+f=ju z&&=%qUy*72{)fU=5zxCVR=MAsMDQL+m?ZJbN5Uo1f^oUJCT2@4=aOiVOSi{z!U*^e z8J*uO0<8aYnWHwpHfrZ=^I=T4!BrA7m3~1k9UUH{SdI9cVqMRKY4e>d>K1?ANAP)F zO=td9`#fBKFJ{x6p1oayh$=ldMDOEhjr$O|j$DFoqyv4WmHiJD-d+iD2#hhrt9Qoc z6q9J1RkAnGbg$))#NX3cm=*m?a;Aip`gSU0!+%}--Z8u2K9NvPMZ)g9pXW`fcT5Li zXYG`hIF~MM$|?L>%d1=W+eEXC-gqp$+&z-8NOuRtt!S?Z&Z@K}he92wm@DUbqi9(k zac?mso&hEG#^!K^?4#w0vAusly8hd@(xmGMpVYPr%dD|`{lE=Zp2eEhFk8z#10cW?xw?=T5pTa++&t zI79l#>Yp~S{ufYD>B*j{f2*8F>F|GbPu73U!1|Bgll7Mjtp7K-eD(x>Y&~y+oiCeQI zxXe8-Ww7tF@_nPN{36P`MSb(1S=7g@)S`~)aehoj+sLQsVZ3bnlt;bss2#Pfa#_HV z-_KW!A-I*zbPHd0`s;fa>2u~@e%>X!v9vQD;OE}m#?L+X4#dyWZx4!}QivyTXr$q1 zCgpvh=P%&rp9lkk<0n!V!p~lOmBLRSUk3PzY}+IFNk*I#0Wi=W=J=o7FWBp}@7C@} z>6OMZS7wp?cm-$QIm1`}m570C9q791Kzn7ob+?%O-`g|J&uT}eZxcPB=3-E5XJ2)! zsHf4$-&au%ToZITIj=^Vu=zKve&)%&@?Y1Vk0Rc>AslHplI4cwCnkTC`2FE#E@4w$ zo0YZ;eG`73p&6y$;>g<5Hgh$SwY`d6Xpi|B`CQ1~n;N~e4G^Cma3}(l=*K@8IM^pd zhDL5^*(A`ppf(by+Z)iMy<=(w_ZAT^%CtrwNXr;IDSb^D~_NOMOF*`UDFZ zZlNNSGVLVGpXZ%*)c~FBa0lwh3{u1LCu?6`BelQpuQJ>3#rTt<6W$?P+DPp|BWu3_ zKachQOPTGTb>)Ee5BJ+2QEbD=+Ryjf-}nB^_It6WWcD99P5mEv`@{Nc8u0&2X=$iG z8cB{|K>aZM+DI6Pk^SCFSg&l+_Z z9c6W_Wr2;)f2fh&RfYBMB&)Lf4F~I-yo!W7QN=qL#T|RIzl&F@d;#kdrw8vGJJ&^9 z+;+2k1UkA=cZx6O*FTx2em-fn&sTm>k{qp0Kk$yv0Z?L3%5kid}K4 zk}!x4cOS+SnjxIP8bUPiyydl&+Br7QK~Ze4)9YMe^>8*=d_e)rh~l*9vll=4x9fLy z;H~dU2pU1DiuFr`BUU`tilg+)NMC8VVej3W2!M*Z~uIjm$Q->Mfx@$P@ z_c9IioczN3$8dYnxhZt!gHBzpI?wy{xrWYIeG89q`-@M7v<0vy>@?`7;DB^r@F*JI z5A-{D7L*Z*m0zthl22e3iRq zuyRkToWL)sdv<))Je^6ZbCK;#QYBJ@n1lU%y1lI7Jb4&v^0aP$l-nfgD(J(H(z%AJ zd)E7tpm8Ncdw01%Sqkfa$jo!+0YpVAHVm=)$+XBh+AS1L)ayE*a_>)HFw}vlQNaY0 zH7IUmlskIMXZH>#kk#;wR0? zb>vt{mC&KxAXLr*R9?9T7?u#_vBiZV{TT0~Pc(LRfos`)?YAFbvAP)frSABg>H;p8 zX3)fA6f&$dN$%@&6c7w{5@8>wjoUlukld0S)ZOP(!_Kj59ksuo0(3J+^WY40s&Yac z0s{6gHpsOial>SJ^Bj%4jz&tg<aVRC+x2YliN<%3(0Tm3FbW zuOwT+a>Ohv7*#zU<>1A_BO)&ro;|u~*PbrE?hwbT4XKXHqxt!q+cg} zJ!xtAFOybp^GR5+OzU6$DCUf4q^DXlSo*#LUOk*jL z+uD~9ghZF9NekCb`X6>QuN4sI0fbK0uim$*^T&%L-N%4;o_F#bY2^7(_xx|3C+b-n z4tW0t&y{-4anCz=UajYU(kky?=ea}A&${P-@tl7b&yTz3*La?)=S}XppXW+F-|e1X z<#~;sZ+FkH@Z7HFTio-@Jm>v{=UVsNSG{-BRGxdPX#CqeRO#U&9@g-%P7i0=UXz0* zwp12J;x($MLUQM;|Hy ztNVn$ElNZ?9F~&BPzUTj zMr-*HT3#}ln`*dR&HFiBHUW3TB)+nn|8Q5dBK?oCXJ-$_7|eBX5(C!fn%`<2Rx0g7 z>{BJ&xO*&<5w{ilBa&AO)lx*Eqpbeod%$O_ztSWL)KSWfMavtE#aPyq&{!OOvBpB( zVk|yHU79iZ+JC5;+WBGw;~@*`7SdIhU%vDcmtA;y)g=ueh6`zmcdP(B*Jis0t zpGAPmx|@l~Gtno&(N1j$~4H>fS@Q3$23)BSX~AIUsqHc<=n zsm~8PCw!~XyYh!Z?OG)}=p;c{3Oh#?B)D)bi5bzAh0A}&=cILDV;_6028aPw7*O3uhcbZb$Ww>)?ia%s;lN|szG5wJFY6ItLez8 z-ix?17u=>(RNWDE(I(Vt(RRFEHO`27U);wfDJj4?bd{?LI=ZLxHnYR-79qQ5$os;b z0(!3CaT!lqFJ_S;wMH+50$0NR&ZyVR!sV}8>naedpUPjuh)ac#awiH!tbQWzg^407 zU2K0#?C&`K#_he(b)1l*LP$GSr&xrKm$RwKm9#Ttz0!KCA==q<33?TG>?A)?G~U-| zQ#yNPW2h`>iP8(JRJZDLQXw@+MtVm^9`aGQmt;h9M$M0SH}Pd?vi#tDO%~BBjHvO8 zZnES>E?gliNjV>A#5K8>kXA>Pt|WaW|I!%C|ImkF*E92{wj(Qwg?Z~(UM!07b`yls ze5#is6^10A!4WdD_7(>1eMP)bQIp3EZ0`*@<5H5=5bX_XANS;P3F32!LypfXu={e{ zF;l)lKH=IM(p>HM->~gnGiZCk{)Mm?pk$av!|Pe1CQUpD$(JS?85X%KJa*du0%bKo95U(ozGud)|-5R0LbyvO{D}z^ifwUA5|nc zt8eGnS+23y6!j1z`1az^s`-7@ zigf6ohpJI|SW@jHV(C410U}z#`Er+e&r6uh8gY{4135Rl&VM%goEu z(0B$yd~K`Xlm4d)ZGv8Ca`sw2*aq$dawF+IaeuSnV+$3Ue%0HI#WFz00Q$dG{li)v zE8DJLp`uTy*zWhx$HN`?A@m+n^zlGQ`F6vDh}p-(4U}?tSd$MPre2nYhfkg@JP0oE zFkclyPFnxhQFyzLgY~3$7YEk=7AmIyVgHqd1&@(eDeP_j zDXRlXDpI)oR{Pf2k_M`kf$FG0om$XYI#xDBW;xfW-$YALYhV1N#XCFdTD4j2*{fAc z)5Fo9vahnwKY*aFrYW!bU=H^sPpnCdLMOMgI~p@g&+&CNt&!?NN=2$=8<$?Atp`d( zIIcp!W_DFXKj*B_5q(?Fx5+ltT6}*qZ#J|5*7UN@YU=gOvez-tvey^3>~%QHUMkPJ z=hxQm*Y*+LAlXswZ&mP4Kg9+WgCqdPSLv@h7~^t8Ep%X#VRn zfBs9JTB{Er1JudL{iIv{bQ9@wFRZ%Y%1G63|rQzgxo^~YwXd9M#qZuW`kLuv3x zTXOJhPdgDLxqml5fXDP7-wm|!DqFj2081`C@j4dL9Z5sL4)0r(5XH;*l~++oE6Xzf z%q9;L!A-ZOITAk0hcbqbTpDoQrG&Tgk`-xmjWyRjlW3TLdyenQduJEU` z(LlX)O*W+AsqmL6JU!Y`bBb`QX;tj~L$=a(uNn4f(`*xtC~BLYQ*&6VP`fL%GAOjh z6^iBbtc^#XA?5%j&! z8DDm+fr=|C7lRVmE=245U~Zs@FEOfjt){=S@v7Ln6GPYZXlu>q$hE$WabQ1^*}KwcNXjif}s@-qV50@el`0tGk*t?dv{7x$bMBj&xJL zHL%u^+T#?V0t|6|Ue3v)>d8_;lK|Z9-m{NWnTy;?2_1N+vdUA$=YK`w ze;20nzca-DL_gwxsuccLf<8%3WGx?b0;c$1BWc;M2dBcfPp-{}UI2FUVN3IVq=%Rf z-+{CdIqIh6Xbsg#TQ-H2z`v}YhO(aEvfXG2;nHK}-AtUk?>pjUC9#}L(!K7pM!F@k z#zP^HqAm1uH7N0lIrE_5NV(4C&h%wI!%!hwWG9LHHI_a}JdgDulO(?5-lvm9jLdYB zn6}i+KRuX##tC?wY5xR8Y1DPPstU-a;~kLAXzUIl?c=@kMK(e+WOKMmLpH^MJ#;Hy z1az~F^nWGY*!T~n&zfp^Co{Y)D){MmZ&-g_h(pD7W^kIOe&SzBuMEXIPexWSYTLLR zsik=ll@1`dLE~St&lT`az?8 zJttPSwk^8ySnHKYwH%FMd2B(0Ok;9V#mq7nt6yYkxv;Vs58W;3vHEK$V`QAWzsNq9 zjh|)k?lhmTU3AMGx0NNhMsRSrXbJDTlf?~-(M;;D88@o1{&I0-sWIbYi8)leq$rV? z%&+%>Rxn!beQTacjBWLsc@z?4I#k*sB9v$nkGiBi68G;h zSKf@geG3zJ2^m&4ZmlBHo?M$3xT`ZkckvqDwxbPn-}~vi$Hj&f8RGlZeTc`L8aPDd zZTF6m$sp7mK?iZ#n=z{TeJBLZwZG&8iG=#aa*}7KRTL=x1=mOS2S7(6y1d+fpI9ZN zq$p!8Ny+e@cimKx1U87ZxzXj=kCUEK!=j>gyMGC~-OawXPnbJkM@Lr4K|iLxk;dJy zRKv?ebU_`B5cvI;?d>4Q(Y!<$WYgH`JC1Tkc?u|q_A|= znJFx-)Ca)`XxZL5Hs7t97hcSeA=P!HtVE}i1%G77BoerQjo(0;G}j>^z-bvrQff)g zu-zGavY6!HPw>02nVI2eZSLq!W|{Skv}T-JWTLHZ2|vFCUVJUO`rzK|hEIwu&vf4G zn=1oOrn#|{FPB42vSs{;wAjH!(sz&+(MW7uOWGzJ={2O!tG+UF^|?#0a!%{3F23$< zuImiWvEN>~ZvBXd*AMww-1@PNInaDE*dNjQ@fSQPBUwLQ#+>suTR$3|A3e2LTzP~z zZc%cvn3!#`xb73l#o|(I?fzoXW=BARI9nMeK+m=^D3Q4`D36t)=DfIl<5q>ZF2^(1 zJ|HD`7g*zJ^juSOtgfPC7bFEp#iDh4iA){%<7ENiUrF8+{{TcbOulW90W)+hYOu4r<^HCOf}>5PG}-9e3x zCFT~^KSveF%w;RRtC2+YyA%#!vC2-W#?7yfCG{sHx5q4Oyv-c=YF|S0Qq5UB_m*&v zga_2ktc_Gf9qjH6brsjnOSoua?{>sZfu0I?J}lo(AeK1q9f$Rx=i3QW8HgQe z^uCSWLV_DXrPD|QmLb~dG|jL<)+D5^T>AhB;z*;GE`K1!3jItjRd(FgK1&7F2R zRa>SL$@&jvp8pM|HMmIjGGkTS+TiB->qu_?JeN!sdEb1CFI0@+iKJJ8M#*8vlhy!A zR{IcXp;u)lleYLl6UA)yUv~ND-}WY%At$Nn>z#DY*=x29e&RtYUhH|fe=^L4dsP^h zm&VMYM85y1av6peXDlqoSXil(;*){nSAIt1<7F6IJY;*{{#HSOz}QlYB5TGLFJ*r_ z#=XbbqD9uO}&Byvaaa#!(x8IGz<{C^n*p4mOl$G?v7DKhIjn>-5URTih)YG1+S z0`93K9eaNwKS22bDBzhWzn}Nn2W%~G({X>=r$e}3c{r$?1)YR&ehbG++fvO@W>&tveotA_|CTVsCsbN`fG+_E>Z? z{4N=ZN}Sg;WFqZ(fQ!jKV|yM*TNrCXxn?~g5^!yL;XYsr3d>0y_Y1FVi#G6x#8?!a z@M7Vj(fv~vM*=a>n>I-+MgG&@cItf5=#r_6BNrAPZN`MF_m>r7A~`7f(FuNghuX(Q z(PF3lBQh&UwyDB9`w-Pt+*9&m;Urrn8!LFTplP0Wvb`yi=-LFa^?4r^S16l`IW{^q zX-_NSRRQ4_P4EQg`s~5^rxIlaxfsm~)P-?$K}|1oopHdOt%rr9JLU+|NiE5maaf!m zUoaJi1(ig;*{tQ|)z_56HkhfG!0>bMIjWh^ChQpZ#WV57@0tv?c@lm@UfWf zoBYggUip;!W>WTcMrVHW0N-@42?OW`YFGeceq-SE(>~>8elq~T1z`XOZ)X62hw@E! z=9J6Z0sQWHTrcSy>)S{X&_Y0-8S{fKU@enM>CcakygM{M#zE}K`7y!XgyzR#u#6-X z2lnQH^W)bt8TkN|V&`?F?k`_kkANe-fw?opLJyiL7Ap3|^7S4%Bo;a~xR<3%U-&%q z-=v#JPh=4LNiV(lQWmqfimQ%b;rm}&#MTpS8gTMd+6Io`1Q!3iee;CKYot{qwQ0fk zGbnyVuEbD0+)U`xcP4pX#txIogTDB2<3V0&Sr;(_vSh+}yQpKEw)RybfcXMhRXQWu zcDfi*N5=e-rPY_l9;84Z8ocy=Uo?=t)@MWC=RLD!qV|B+`CMXr7WN``#fp;7uDpBj zij`MhZhXf~ypF$}LdE(38+ZB#wk*ICBbA@a{N|l}({r-ctnsKN{FaqexSAJqq}DUU%DXJEXH#TQqaAW^WX%LN;Hr@qU?9&;q>V{lZ6uqhm6Jqgq?ppmuL zk9X*jXu)LW5}Uf7E*a3;?V^L>TN}Z7@z%cv*Pa#?+PidMd&lgt_KXXa(4Ix@xUGEo zvHVzh9#UHvq4%R@sEgUph7d*#pWEH|C2G=+&vv0scU=r2*Ax`7W>rtY`Vu3YhY8eQ z?k+;`;D^@hq?_ksYL`L^Im+)jm91c-s-v#(eH1p+gF*y*omc1}itC7LsF&h z5&DiJg``bs=~>|3Up+`APf&urIc-rzWU?u)D^fKX&o&+%C^tnZXayn zoFPM*5C9Fv$rZ{*bTZ7y7DU7EF6{662qHylvkXYjrn3-;*yi7=Lq~;BKkVya%uMJo zlS3ifKPQVr^IZUgE9`G?|0Zu}PVEFjzc-5!^{!&rQA~`bqA)zE%p_kukFPXf`X`lQ z=h$gJ|K|m3Bd0q@s%G$aXZ5I_DOwp-X3{>k`|SPpvCEp^vJO;Mw6E@(yhzoko>4vD zSLM=E7Ns@Yi_A`}Wu$5>?@?XUX}=$j^Gczavxp+mDa-Sx!jhL^EC{jW+m01W_BW-i z)dw~^ob6x{A4uMk-KdiErB_|_-(n~lmcP0APgD|%6vM;ZBlb{H-aaPUkT}C^;9j1G zX9G!M9$EXV2{;QkGB0Z*R-Xq_oqV;md0)~)DC-}g=5+Z=BqqU1Hs3z)ZYYAN^<3@6 zBjBB5`cd?}K*}1gx1yb>SL!6GQli8-K^?&=RmaogjhOv?17ANS2zYHc4x%}gDndka z0miK4(Vdr2RJbgNSiIK?$_MNC8q#}W-8Ot}OX90D?MB38yk`mFMa1Jkul#gT+RjPg z;6GH|E-1neXFCugpC0Y1In0TbLH1w7LGx#n%4l zvPmX}9PcFj3-KzkVK`FtQD(8YKO2AR$J3j5LVqi~tH3n-g6cNvF`{j#B}%BHMRfeI zTKLt1Ugw}QLKKMs_9IAPy9D;g=>1MPoE*bD#@1bJnDB+^GiWkA7e3}d$P#crvi7D~ zdyXUf(|e+0l^!}nxV5c357l97uLI<``IjYrxcyw?Cq=9qr#taDzQbmmE>9Diwbpld zOQf;v9J|7C`$atY8(HOM(;^}Zn9?MP=vAtxqUW@ssyxV5>2D$0XCzfx|J5f3eCx+t z|A#(BElHlkCJbNM;)9{zw)%X(drmyMc`@zVDR2E={W!3bNEB0`!uus;zycbpkMI~@ zrN8sM{24~p;$~j|;e2Ve$wFlb_pLWhh5=ug^FvMliN{>SJdAWauzO*8%ebD}b>LCF zI1fi(*Yc0@%6;`?Y7X$zV`4?T(L$>?<#{tI@@fbGd=;U3GhY%L*JJN( zo)4w@D^_aD5&PobaAfY#_+?yGZXbDjx%ci;4Rb-I29M>-jLGHRXqU@rT$8C0v%xHW zP$IEGyCN{cw&?a7l#9sJUS1h7wbKQ2?;Lx*n{|KtC`zrXQe<=+L>Es8n7T)DVwM0C zP6}Fh0t?!8)6*8Tl^@iCrXDhTZlf;Y#qEb(O!0Q;RN&Q+mbF`5xQ4X((JsAskIO`c z?_L^o{At+u<3sQn>2!%|OuKy?*@0QwahK$oUJoPnAreT4(BTq7<<@e?&UTJ%(g_GV zyzfy4XA5XDf0Tbr*G=TAGLQKwGmd{eSGBUETOCRpKLScWfN~#_5oS*mO4SKa`f-)E znQAh^FDSnioaXbkh4h||3Il({*Uq{s6kj`@A#>PV*<3=i1Ej6Nf@>efpCgo|d?AWg z)ZPW>YoGpM#eqOsFt{%0!r~0ShLRAonA7+w1;WKvZQ-vUV-!#5!E1v-Qj6#PM$X)_ zt)*ohrJG{)dEg}Q5?h7d`(*&Ie23}rv%vJm zXUasrluf0G&QB%1C*-n#b2)q`!uVF~mAFOCP0a_V(4AxzA#AtR3ni3^IHpk{cP9j= z4YxPB*_}^M$ULppIxtPFcw5q`?v*q?daS(0Pqw-;x^=HaH-+2u^jU8^d3p06O|A z<-hk|?;N|WNY?@86Eb}lZ`sSeU*Wyc{1fEfujU9m+Zi-S;bpGy0V<4)S2eo(03E#8 zXWK9aDPL~o3+p>M2+9QjKPK-yghqTp(%5qZrD8S-Abb1eoo}}|z}2w)Hfo?%_UC$W z+XR|>iwXA+6xL71vD#)=I*IID{7v#?wzFxkJW;>S5cT`CNTN!)!V-xHue_&VWXys% zS8@6|c_v}($RYZh-I}(p`$>;g)lYV&k{u*jRSXUV-6zzf_v}72UwPQG`y1f5+(e67 zUE&SPNbP)_U`>YLh?&-S1=n8Nb=S0qi^{H~+SFYXOQ5e|7f4Ptr>({iUB8k6X0Jxo)Y0a1bJulAChpBHapleGo*k>wvoes{^Z(eLQP*Z?Ks; zTXhHCvdA+y&*IxWf8fw@JgRY^rQJS+@gslD7=OR@4ZC;1UHe8!on$YlP zZQ|chsNcjx@62q%y%26uvvzvZ|MfC3Xili#%6h4Aq0Nz(a73l|KMO3Povg52nSv#b z!kOOP3|RI@%->B|L~vPQ`5O$(V*eaJdl(TuDM%S7dg2J2|BE4t?$h{_!Af^f^$b|4 z7SKvPBob?OfWf?oHfJOmqvhRjv{fw;q;evGwqgcLS;ES_<1L^BtIT2^_3GjJPmwZG zQdW5)p@J2aMxxh^duwetzb4-cjd$Eq7@kN%B)=0`0eGzG` zTUx=+BQ4&lGK)!Twko}dwC1$ZXOI@S8rpfJH4GY{xun&9m6@ab3oeUXbnc~>o*OxT z=|%qTd?F+xS6yfs)m0ZxbGpiT>}Lr{JEpH~rV^)N4D|P{(NTxjFmRY5yw4hVH%9-Y;X;Vw>M*SU2-sewBr8&=pLUs1;lZDH_#DjaO(>M#4-~koZwApKL|O-0;k}R3IoEk>m2wmE z_+syjO~o2W*ktZ8BOCmoNn?+^9U1*L$T4JoCr;9kZ@>>gIi95{Ow~v5JT!Y7S$idF z4`x0qlc^A_xHDgX0urAXl8r^ZPeK$HbQq^8G6bIcd~5A^D>iZqGGb`D@_vH zzEajTRmPZ|HiE_(5$j(IpU{5zJR@TRvuRssBupp|Z50j3ME<8%Z(@PYQ@W@0^TgPa9dY)}DBW;lHtYEI8mzeaD*js%hU5vKZb&aYjNJQ7e01CXHzk{iHhm&sBoQ`z!;ltAGofQX4 zq){h8_oq|=E4F`@+B(W_fHY>(>iwkGla|b}f%L_Zi>ofUG%QVoN8-(;4WHxaqwu*= zQd9G%Xl?*X+v=rX@y0j3{SGlciQG%*P}pAo3#uvi7PwqcF6vLzE7vy1;BjuTNElAq z-Esr(GSDmAvF{w5j$G)z1he_xKVW+Cgdj09m=X+}!*t#PF#YJEX_)@|7-3r71JnON zu@I&$hOB_n0iHidTENLxG=a3)>i0aVZGa5l(oc+j+nWy{IRM#?ey>7AUNTAaySd!U zho(SrT}|=M>Ov#dy$Y1WSvtiKsj6Ysz+~_Hvso^5cRX~v8O#+|RGur!#bTdC?VnI{ z9Oh=70p@NUpN6@+ii9}<3g&)JQJ+RNlyfM*8M>TAdOqp%E?@eliPG?qPpyWJrsj80 zXBK>%hklwQxqjd?d=v%vShU?HZ!C&6)hN#J(P4;aNm5u@<^=xz2Lm*m{3+0I6Nc7> zsY9`Uz*?TXn6HtdLW6KHm%;)4EF}GA$;JAwm>TQgZKY-DH>m!qi!EUuF z)e&?);8=4rJN&na7T?6e)F+zfKP^m3t6%P%en%Gz7lM#4pn`-Dvg!aKL;yn<-=eAz zT`Z=2fRm-9mtMX5{w~8$3xI*2@Oo!qgBAFSWUxLlyngNF12s559J0O~)%S_7P1q+~ z-#s62ogAXRZ4N%}Lme1zVi#rIIh#5V+Af5Iu|g9_rI}kl3D~`VzxpyZUBzi6ETcT( z$8h|9w2I}&BLhgk~U&*56^_%lF}{#THfWm9iA4;5$1Td>jm_^aDA-n$pBXb90qAmpH-8ys2v@){uz)?HH)sTwbj5@M*fm-Qod zYby^iBqckaz;5@$!_!;;CeL(tm>|(m*GC4=HReo`rNmu>DB8K`^_S%c?Dyh-e>n{U zV|^G#6vAQc%OAjef?kJ>Cwm?bQF=U?SgDHzOCDT%>jba>)*QeII|gl*bE#azt021U z0iu?jl%FlSEO{91Y(8^LsB;la=oP*UF`=S;#e~eO(d)fajhm(`{y@ZMKO9*^}&jPD&mgD!}f7tUvFQaC~?Ja!;E)n&XERsC1yxi;G$N0a) zQRHlJ^h8M-j(YQjBeldNdGUP?9v7>bPjT({Uj&YdNiWTQokNInUDDw9ciGlYWm?-XC9~&q{BRKu1o@9(yKIOK!Clu_mZL_r{=z<@Aj1ehh&4 zq^?OdL~0PV`rDRSn#Z2`iTZIM&Zc1*BOuODHy;#j?|uE5L8t-eMzAL$}P2Af(81$6=*PMZOh!e8jqk$Q7q0r!sMu?)Dl-}xhwTA zggT>3Uyyr_XU&ye4ucv%2X8jR=*Rc?LqDs-F8{&y3tfhL2p(*~s))Co8@ZK%FpXgw zxJ^Hyc|UazKBNGYZ730|9TxhK>5z=|W^2k{`X_RU*SiiZ`Y+bF;tyHz&GG2w8FuFD z)m&w~xzv(`8mShE)O|_64q-HlUrDbaJ&tr2>8gvb zxN5f#P2PpUwecM9^v89#n{2do}PzqNdb=Pgw-<+!bU4ldBM)M_|DyVO%LBQUIeyaZ@ zU@Of__BAUNOW2`knNa$%Bp;;(lsXmno2Z_~vg`V@bL@5tNyvlT4yItP9c|_xaCAc= zp&FSE9&`7=)1n;cYnsI^7Oa60EFFU_4?&#WdjL+-~Ro?KfF|U<|8=HHw8Pb z-C=vl>W{VRi<6Z*B)hxWQKrB#)W5_yYiAn!9&8lF_7kc!AU ziU+jaLR!5MkKRC9u9V$94}2F$`%M+K`LGRuO}^UL3HZ&QpkG7Ghd4f)Bo!+zsoXml z1WCIy`mih{LAzANr{hE4ZFH<1)(MMZf;>}^D!IHRQsp$XL++;BUWGABiN5M%v}EiY zTjj>7^Wax@u0A}n44Zq2cDr2R^FOj_ZblB9PxhYD(ybZT{R{puakP_ikOsfTCp5U! zMXnT!XKT`MmON9>pEj3K#*c{Vi@V^PWbDd3`@ZT3H|e(E9M|_jA-{qnDI`B-9($Q) z^t?YAOJn#6cR$Z+vvLPIAS6Nk0llzEQ_9ih)Qh0Y@1RA8=(1_&%h07p54yZx(yFbM z`e-J_)sSd$4(SZH-kYM8J@L`VC}NNzk9COdB#)^?Adgv^$DT7n^4LZOPx4rKo@*#1 zkg5C^k4U5hvRks1b)X4VlF0O3Ad$JeQp@vYt$(A2q$IMNi5=1OQbE6z-D|ehmGULB zN=k(#vW5EUzfmGH`WZ_9Hv5Gqzl+m^y>n2w!@ADb2`*6&2Hz(+vickR`n@RYEv5$+ z?S8Kc5h>izkwZ4*Po|NzR}$*a>*)UBW*$Zq+l~I1y`l-wjbLC6-c5P@ zQ_L4L8@LMq!jN6>J{2jcCxf5R=| z)~Ti9idv__t?m^R_g9^JDQ=c@_PVB&hug`O1p0Sj-+A1&+d!y{@4Kj>jMl4c;3fok ztgL=(aqB?B;N#A$#FU=r7 zm@@MiPNmfShyAACVS=9oYLnMUq9AfGHuibc*mjxE?AFLBd5{ijWa!q&Q*l@M6cgCv z1KT|HrQI6YcRAwAGkc|pFRx)EO4{ak;vjKs%=S_2puBAJlc^{F3iQN1bZ4aDtBXn< zzJ|ST={s^Iu>pyVCu~2>H_V{_rQNr*(#fGGs0Z4sG~|6t2T{sNborkHC7aQlLlWKJ zUKUCOA2iyFwC7Ob>|jNF5a=4?Nbd>V!tk-h;UiHqBUw;+oUXYuH?#nUs)V2x@kX^N!m)}_n)^bV<1}VEMNDp&m{HN zEvCPo=?q=0j5j3QHU&2zzV><^u4}&b#fqdNXWxbuxfzs`J!T&;Co6Gb{l5U#2^rc| z>x(SK6!YzK7R&Ee_nYPJ*Xpj4{$l>ze$qj8Rvc7kzo{ktG2UShTm)clN5PB+Ew5D= ztdkkGVjhpgqWe2o*B9+bi6Kf;9`ND`rEwpHjup6q+IvnM?n`XA?pt?9Mws@Frh@ME zPz~sEYX1Oq6<7}n>uZ5R7IWPJK#Pc9oTX+*h=nWs6M9L{e9Dcg{v@T?DZq(v?&y3@ z{_@Yu56;aW{4^rJ)^I#b1GRSV|7q*1+pd+EOrH10KfkOvVW+u#=r3L&V&{7D&Hk)^$n9-1Z5Z@$KpVMNge8c_j6;LK56?#w?c~al=ua{ zMge>6J%Pf3X*wB-Z9RV-S5ePJH0R7Y1Dbm<-_@~cO8e}NSwr2JIGSE-M>e#P&@4JsVb*WSr!Sly@afm?6-uVuaY z>yDRM-Vq4~?Cb374J|$YLO_(nQyhWkMDtN&}K@*K8`a%tgnrhV0YP&Jv6*O%J zMfrYf?R{p>WoFJv&ZOV}|2_R9p%RkX^9Lt;(R>EoOt77Z z72#dbpACkU!8mwWP1m@@j3BzglbcgyWSg>M9Q=ni)JMz)=6~C%Iq+0Ka2Cem(=`cM?z6(l3_=Vs zy@3x%Ox-Axb9+pbPv!hzHI;8D$&CD9HeaL#@(1V>g<~C(!1!_^EyP$)kK_w;7$55A z9U*lbJ(6no!ZIk$ou5jzO4@%wYx;Cel0ioP9{!=~E?WEmLL=b16@XIs!1zrac9%Z^<;bD^Ntf?FhY$)HtCBtuD^N{f-H{$(K1->(&^_}>};GOp0roE{R`MjobFZxeANNpDtKYKTZ+x58~Ka|#*9Xe z^cl?vSIgW_0XiCizJZ@*m!^JSFHPqsL=GP+0cgC+0;{?qg+S$a{x_fhoxuMV^1pQ4 ziS?v9xmF{Gv4j{-VK6iouY#0~64k07pyx^kg4wrx3>~F&R~8Y#N!x<*+&i2jhV<5Y z*poUmSZ&qxYkb}Aqu&~^y^1;>{(!g;kI@j+OQQ${NpF3y03FE2;G}JVNiXoGH#Jg9 zz=cK@;vPiJhEd=CfEY38dtnHDyJ`q}AniDLh<_=c8ox1EuzE;Ab>s&qr7GxKHN>|9 z$Gna9ZMy?I8PQ#^U>kK`_y|uM7WZX}aJPDhue!IdYP7GJ-lRL6xj}CN3Z6F6n@w`_ zaHRR^cSwOq!PvM8E@LS~T1Fz}Gb?GFK2^1UB3-JU;`o8`=}Csub$ ze>8I$Hiz(d@j(NqpuT<@uGg#UU*lRk6XYsfFU51p3toxqF}SA2a5=7tHwwfGaZUR? zVp}7m4Hw=p!?SR{XW{T}uLW@A;Ql}MlCyZBm|{LYz{0pb?ij?O`lz8F#ia>nUo$?M zLMP)ZQA-A)bqddNzcj+i(8K!L4C_tyd_06G~(ejISeN54QV1pVoX2e3}QAr}JsYw31IFTA|*7iZ8;~f|px?kVyCf z*Cp^o-E|X?2lC~6_2bVo5yQx6Y6-fQ+G~MDYcR1ksfy&wpGQSTo!2EZ(g#rcHfN-Z zP@ux1IGN?7zOYan2R}{H>vxU4hD}BvZ5{-NB*9;A@QB(aj=OZkDsB9@4PT zdn)h!4N{#lC_<{vLw!z~3}ymeH1ku`AzFqU{cHFH8NyYZp=H7jt|SWNJl8e&6^Lh5 zY^9LMQ+oC6R5267Y+g2!3o!*N>0cUk>#O6`#S3W#QvgBLI%!V^;*&y7y2d4qhcdr~YrhA@x)I8{~guZjJV* z79}rA#0EKC8mP?Gebbk0H$+cVX+xFQRsyy)|MSIN5F^ zZbsH2QY7Y95>Yb)sTZr`=$J-r6Vm3dNG4b{d;p&y6GmTD)b%P9w|%69wU@{X(Z7L$ zR<-}=(->`!=6CNnTz*rierfuQ68^NosrVO$xX@B-q4*CY@#4BSfAki4P*e%9AWXiR z_XVWH!VB;;VmXD_FYY73(~5_;&+V&i@clS;6a&M>M_9g7YU?KZ$W-&WN3qFqlX zWmJ5X62QNUGdwqs#S7^#d9j^H`b)h=HPx@!;HRpL-Drc7k~;VaeE>pLZPSS?dmivZg;_;{GuJ_|Le*|Wd}2E0O?`C6n( ziZO7bCkH#41s98o#(}lz#71e_w@*@;y8!$DQUSbi>{L9)s1{e#)zw>Li|Ii{-P~Y7 z77q8#z|miHYK9+YXLy4bA%U63?=PbFQE<)$4$5taK{B49qdSR~$!Op5?9B$T5F>i! z>+r2?zbz}!e*2)T8#|w!^&Yif%G*KC#~?za_M1WXo;G~h0L@UF?ZEX-GfGNk-Pp6| z5J-J3(d&y+rE+w&wl)i-*aeHMue&jCiNq&WLz#+T{-S8sYXrtRl%Z$@JQY*YY|K{P zyrPxFItP)!C|_%O=svtc(Rqw>`Wk&TG@hq;oX)Xp^%svh0=KjY;i70{_9pd5i<>fz;e-ZzFkvdg$`(gbEK7Y5g=-9KV)%@T@_|W1xo$VJN zyh{ku^w7Ve^n1d(oV4fddV5yYg|6+-%SOEkWf--$ZnGFsAMrsn2uWYs7usy}k;lZJ z8u}vxZj^L*N8cCZUejlRW*BQ4@5DiPH{Y*!^)A!glD(z^xLvs#Vl;BYNy`@ zGDR}|20yUy_Pq*AGcx@M$1o8MLl4>#R$-~ZbIwx-3u=Os8YoaCi~F(-P6R+P1Wud#*G`O9FgBtO#gymB5e~p5IYRo& zrp;F20x&9>G9E!?Fd^=Gh4W)-P&yh>EK>ix=vy6)?SVddWtch`d-gSS z4&%WiJt^EM4#5|6WFxFq{PvHyw)7e}F5lnBT-tviaWu{O>^gE6>9?geXLh&D(&Wd;k&u8%{-j zM5Gfq7Ufb(dKUkZx@{A=hY>|k`-3oYhBX)lrVS(kurC4x%;msC8E1|C102Vr(0**k zvA&5Mhgu8w9Ktc#Z$KEHe0-_JS(UgZxn6_kcj1~$gkp@vxF(`07AwOw_scw`0J{y8 z%qp4N{S=);Px61qYaBn2HB0VLek2$`?h8PPe|L3(fDOZ#dN8dC!aRzGgF3xK37_Ci{!U`u>7!R`wUoF!tE1 zZ%y-?S+u=TCR4GsuG_%D(1*XE?=~8J>tWNpciegozfoQlq62ZlDBt>M_+1t7-5c;N z)0el4SK~V>4)Xj0@e7EHlS@_9{N+=;-sr2o6!#RQS3xD~HI*2H^nsrvlOzGroF=gZ z9vRVO`sU`!_eu~{u13xT%O^SfrjrPGcBRTH!Ab1@UvdWYP&$Lc$Dz(;JL5Tn#~Mhp zdm&gv5l;GShHMqSc zs(-O5gb`tBTWg|~q3EV-Wlw&}tqhZ^xsysIU#z{NI_|shiYx}{YcX^26oTtgR)FbE z5bxJAz4@S5ALsXym}0EPVt5n|N`G^2?Qu|!7EV$9Px23I;*tdByot~o%1&3{Gq8&N zUn!I=-%9_|^qN~vie8tTUct{VDfyLrNTcDBjP|MW?rcmgDY*dCg)l7I4-bK}t>p5* zczdu?4XFJz^%C!c^4!xT+ZF9cQnXHRZhQu>=w{4Gi%xqI7X2zZQFc&~5LkR7jW^9B z*8pYVwbiiKLa;Uv*U6ss=1hN8sN;}1u^rKj2Ng}618VhpJxx-dz=D7e^{efAe@LTd zXqz@$`Ds+yk-kOe3LDv>;2n=NgMBEiC|8(-F%&wg!jRm`K&<&QV^K%rglIaNU!?JH zmX-#4#erJLYbE)Xig!{1d=cWTgct}kk)Wqp^u;JJGE^G=Cz!-D024dnc^M;t$fhfG zAdcE9nS3t3)5b~TaXqaEeHYscjfq)f#(X9>&1(_HsVezVG*-oVxu z1$5{$)!VFM zd_r3calH3BffKvG1Std{ed#Am6kf=xs898addQE5yHknAmGp05Wf|;7mYXFD+S{-s z{%xWNY~>b7LlG+YVyH&na7v~XX>$osD#&{PYLmiGM4Z{ za4RKz4n{#xRK?w>po%xrMOq&z0z! zhxkZH+d$Z|iR4p-ILUzNdGvZzQ0I5>>#2y`+gH(>ouU_1g zwE^AEnP{rIq0%Mjz{(pMU@&mSmlJsOH8kyZEneORifL4~7uPS~8h+LDzqnqduD`-H zwL%(;e~IhM)$=x7PoHtq9M7y9XU>!J@sfUC-v1q=>Yk&L`xD#oLk+Stk@FJL&?(|v zQ2(ORix9GwmwBmvUV4ZcU$mboAO4jdVlxIFQydy&O!0HXvampG1c?3>)6DcEi^K67 zb>>}Pu;8r!6^N=RHXUoICagkHhU_+xv>AT9@kWf!_YRKV1ogVeHOP?$8YFk6*e4*! z$Kx5gn@CsMALL-vONXbYFQubNDt(Opxq zxW-d*qI5HKwx9%uv3dsj^z_Yj2()SSB3vtqayyAwE)e*|Z^1Wrn)J|8X=s*}hGto5 z=&DR>vD_6h-TfzkmfmdcbMR&}5#;N<*^(E?n~|2`&F;o0WQ+1F$r8Lyc^~psOK{Du zDUreamw#jX+zaC5c(}PX4cA(57#R->WOr11Ra@?0=X$)zS)iSq1=>mb!%*`)h`|dM zu2d{;V|DJN&2%z?d`>u4uZVLWMc;u?U3Nx!`};0^X4Mi5KvtHukK;bx)2xomiZ+{-Wj!V%~hd%3M-`ll~$) z<7Hdy8819otD$)=moTQz$O&0kn2I%Z*bM}-N2vIM3@yJw^o3y&jo6~OZ+b`I9ksCN zFL(!2S`Vk45ZB7jUXh<^ZcL{12&Bg{gRhzAWuN`S-nlGCnPr*9zi7^ z&~plRqTxnQ>hBdj>m&4FxAu#PB)yT`hB(oIk?5L$GkS^?J%?ko0F;fM{8fscxr!bm z9pBI(-QHM1hco;wq!-9zIpyOCf2XFOF$%xge#UyqwHv9r#xYe<0Xd^DSJAf*OEQ?g zjhcOTY>I8)vFO`^frm4xb(Owq%vU1$O%#g0W=(#p6n#cXo#B`gXY$Eb_;*m2pY*pv zv*)=Af1>ua7J-~oxj3VzitGsT$kXUqrrGn*nDRK$F$K=>dlmkA%BGV%JR1H38)Msx z^oPg_`qP4i83BJraBLREK1RLWMyU!%?M|~GXY>}4T|-`n|3lHc?lIN=S1EdpbbN!- zjx#!(;cp>5QTs=}n&mZCv){Qf@h?m={vw4xQ^S8i)7O}o_`jjSh$B5XfM zjC+T8@G`0v9)Nj3lGqbRzf)~_LkqycDz4fng__}bMx`_P<}!g{v5zw1)L%sMr$e8% z@4p(Jl~l!BgQ@uf`YYwR!JRwhF`F2#E-%fNO&wh$>=kq|E$x~2C2=;mk z`E8PCB>y|~DNUZS#=E!u*|{X8RHZ!kxRd87CKr{gQj+b#hL!2&14OBD+P?Qwtp#n^gS4xf z0>JJ2StJH!^&5Mn`W@KgZR>kRenm`RSY%Rtf#es>zyC?f&+I>A<+od(=_++vd%wY* zd>^I)4di?G3Zr}_MY^?|(BY-|Gt<*ze0vNe+@N-)f#TiuO-&JIOav{}}M3l&`7% zD?03ZB;`Nd$!|ZYo!URrw)*z}7$(JO_WAy$4&-;+x~^J)Gy5!J0@41dzCiMe)Nh8a zmGVn8KK_cO@?`h#UM4Us>M2i8@{HD> z5c$z~-)N7I|Iw)grTlJiC%;*wX2|b~`;GE@_VuXzp18z;J${AdM-GDcF8j+Ss_(#G zmQ#M8M zNsjM}m_XG3D9$H&N9unA*2J>cZ=R5JIQF0JbO}$CLab_2UVDh$X)>9Md7?x51tK_LEv+e;%Z1_3iiFtx@?s@hb=RciUq< zBflah5b+P?{Yie2`u8=D#**JRe{f2Nl;0kA@~fqC4CMF6-x}rj`Ie~sj&LHsa~#v% zwf39M1j7GO9-ibEso&3CCFK`8U;Ol=PUWbh2mSG|+gIVG|@)=E3@j-jOOB*jn=O6rD%F`VG#2SxJ=rVPY@whwr9>U~zhzz7s4ekBq zsC?hJ$bo$C`Ms2Hvd4?XWT%ktASxS>y+-CwT=R%#ukq(kbUq@fvX6c=d2Vng&ss_o zQv0tk$+I>p&y$?U^BhHavd25wOkh~NM{zsJGcy0OaGxDsW8V=-{NBMh_XLSC}?_$~GiH_+| z@uWNX?ItzD9zVR(D8H{aN9A|D6Zy@4sAuGt&jf}=3e_7(ev$b@iylg3j~}n>20b*s zb|=q=NzIVw-FKMei9PJK{MsAX=MZf_asBL=?$Ga`eTPYou*c`L@nK~C)1sBJ?C}94 zvYq)E+b#hAnpG507T@Iz-<^M){@d^-w3K8ko=AQumD{rdf7(>a`6nyuVTCd`#Z)l-Cb+HVXC*l{x(s*o#Ypp z|F>m%Ecrcv#B^8Wx5u6QCNp^*;({`x{LYh$MOc2{p6@_@AK&Mc?ykwNhUz|$-$IJB zNq&*}i`$mPlHWwfbSVFKhdckrW3VwCTBa&kP&_XsEQ{R#{!MRp1KH{-Zhp$uBzpI2cQQe?wy0SxZ*_(VhIBBDF$(56w5qZ=Rg& z$@072iTqA;On2Ap&&vdc#p@Jzll&s{rw`mCeub%#)KlS)Om4=fEC6uIvW=iO0`8Ke>kLKG>v2tir&Urca=4Uw0KfGc1q4TA@$S z-NF7G;LF$W4ORGj*@fayh;j%wZ6%U5QBV&sWDWG8d%=aO{wIiphBjy^X7NhA+n+-@C|FJ1}Ku_-d$5l$gIM zUBG8MA3vY*Md#zsn@OtoVm`kAN>E~2gP^A5e|nb#j+tLu{7qE3!3=P1J-|m8;7R=N zFT^h~)&op+f*c0t41c}}|4ry075`Vn=f6C8{8QaW$NwKM((vz?6c_)sj`6p7)PBHi zwX`p!nxJ3HO{oB=LzQPDPe|=rgdhp1VKDBoA#9phO!vGW@G-N9ChT6~5(^8uo+4!q7^hX`&d495ToNv0gEU!Wbhx z`Q4#suSSny`!*?`VN6dNFIWq(Tmma;(F$l(&$4hASecD~rQF1EmxHXm!SB@Zi-+NM z$lhbW3%p1i1-9nWo0`PE;;(s8CWsISwE{fCmpB%xPQWbRMEqP!r6?TVN&`SWKZ^Eg zmr2^C3WzoFx5aqWBre1+7B(~`dBx#YHnt!=-BmW2{sWpm8u)lQgS|dVB_M7pBu%mU zdM0lDjdX@5>447gq`$O#oaBj)SB(q5%;wGkiw+Bh=)KV_{hJ{9G~8*Dr)w#Bx?*05a7h08Mct6RY$W#lQ;Df- z{0C`N66JppZhM&j+uiYxY1mT##{J>BKRB04LTF#qenb!hHrN@T3R0@hu+-EuCZZm? zV)YPQsHXvGZKn-`^-(A33H~thZ9`k%glIHE%iVBXn$6P(Kypk%+pMDh_b%Ztw}C&}CHxT#pLW2@z!)G6 zTLfZ}-aX7m1}j|g@jmj%aTK0VK0B!Ff}sWu1O&i2|ttJJJZLrrM9xN)yEnt6D5$>uk3Lo)OVf@{Pq%C z9umUeMP(X??fp)BT(r#7Mw(`njeDUSg zPJ{8p5pP0y?V|FGLw@eG$7RdU0>&4gpJVNDB;+U42L3AupWMi66BUdSwD+rB!uKeD%&LBCuol&p+3rO;16*Le-OiWCa>4#xtG@_&TquG->dC$B$St* z;XC8!YmAy*>z@WnPTPMH@GW3`@#S}{J&uI(%d~<2$_=(MO9+1xm1`2Tm#baE_uIh# zey%(E_fdJrp}z08#})A}Sr~(I{$hRYkqGs*F(Z%Z76T`5HZb5!8ZV{>eBls8DEe!+ z9U){F#g8M^uWiV)<2Y07F@n=g`Iv<*L0=O#V-NT?27MbbHra`>$(D)YQY73t|GA~N zZzGRPhzyKEKbT`HC89j`|KjPN%Rrk@-_ehO=GbEbJk-b9^z|_{8VW7$j0~?WTeH+M zzC7S-$I(*Win^fz>8oetMukbl{oHgl@wX zMDqIV?uvxvK~SJyKS;Lhf5C)SQ*nm|qpOj1lrvtjM|<|Ce=14EaU-!6WP0k1zAzPMh`wvl0or_u7Z1hroL#^`rsJQF&sr)qbYe=|Hru|LAy#Ezdcc@)Ji*wuvO`L7P%!y+6DD5^ZCY(=+(ce!~@@(U>Wm~Wp8gN+r5oUq5O~aX5uy7-oU8{Ehs4czFtT z=rZsF)tLA>_cvYAOoSi!kBlXe`5ylAjzZ~fas1&_Wcq3cqjf5mJK5q$0yFjo3WU_+ zH&lzkac7&*NO1@dogG9c%{5ol!7DfL1vE=1te}`P#9P0=SD;`$&TYZ5Ey0W-nf2fG zqVw+n;Bky?M)_8k_7Ts)0D`{Nd}7Xupl=1VE5wHr34T?O&pU1v8OY)UDi?uNoMayi z(M9O;a-2vvpB`1xzX3k(U6uZ+hZW-InklUhuH;Wr?=J1 z(-{p&_KxXw_$x`1fnkBFL7XnD7^1q2W#Fqc9Q1}aElN4q+7m_ z;#%RC>@tFbluwPwEVbP1-KWY9?~Cbp4K69cv;&jZ{O{e${%>qj?Dq_+Uy$X}AHexC9HV)qa7e*&c2Io=akc^2-SL4zCJEt{$AWiO_u-8oc;NR>3yu8#{ny>&cNf)H z8bd>06W|#cY|+uwbJ7T@x*DUK>|BMq21D9zAmW zM>QOZPKE*`xYu($#Tk}_@cj(m;1j$yU>TljkBHw54U*$`F0_TIutI7J;ly|lp1!%M z^6k=I?Y}@!UpPBU9OO72Cyoz=bAZDAV(Ar1sv&wL{`EA^M+%Ec@KO2}Tzm}+*XeLb z%GZ|Oe2v~=vFJ?`ms;o@Y^3+eXB53p!o%q4t+~1<=&hzg56O4?Q8DD}6^{)kd(q3c zVUj_b*V7v=>Ir&Vphc#)AQrt|@i~SsMtc}TA{ zx`o~^uzfKnex!V7Jgeke3IC<1w;Dr3ia{NwpB(zLvIR=Mp;+{K#hu*m>g{2vk={NV z6}=z8AL!{7SM&tEO;ng6`yCdG-T~s>A!d6RY@~OkM(@ccdUJb(-fWHD?MKA02d_B6 zLT>}M3)b1gq)ke`-y(&tmv7aio{(=b6^hvZ#-?}PX=eFOH`4p1M(>;OUwV35F7F9? zYY@9Lz5Qd;``W2ydQ*+`mOiKCd!&ipoF1XqtI@mR@R;_HZlQOr-(U}Yo>%n#9Vvdj ze9JED3HcVm>ZJdTP4AQ(vwX)J>0PPO`y%|8p5CU3Jwfj}Dh`qT?#YZP-)B!T)BA-= zfdp0m_JWdc9}~UVJwk67T4Z`dvFObZ2Y+U!cd3!yH#K_SNBUnc-(r7H$Twf3cUUZX z5&v4~9c-kx^hG7#C*i;J^wt#i1ijT%v>|)go)Oa?9y{4A-v(@ttMk7{ZdUZ(grvWo zUT=@kE2xOW{x>$gUk^6ZJKad{lN!A~_%A)ZMVI!3d~-E=`^TpDJPW<4MtXfODfzC1 z|I*XD?vkFMw~9(PB;O6`G40|0lg#p6i|u}O_V9s5@0aigdV0eJJwa~^m1cm@-3UG zYG8{x>$g^G-0!ce;^Y-z!SK z=c8tzr?=&zo}jk|T4Z|r$D%h)ymq{q-c%#KA87PGXv&}E^a#CPjouAuG3+5jq+94+ zi|t!={FI5{uqWtU zN0l0~-#v%Mkgr!fJHSlu7d%5J6_qs3r@pAs+s8z2c8|~-raBAJ8;VWu!DG$zE;Z8Y zdsWGI68x85zQq^xgnaWgdWXfP_fiYJgN^ilpwWAhDc@J)>ju5?>V0ddltcA^qkhR| zz|#x7qI!(6JTqS6jJbR?UOj-*_IZH6F@?oVBw!-f{_#wHOi*0RNCUZw@!+vD8uTaV6Wg z!CPQ~cd9FRgDmiP@pkOWudMYYY#%$2tTgf)$a5pVatpjsuHcQZz}r364Sl;%tTFQY zuq$}WE$}XK1uxG6Z~u92_}z!(qmkdIT)|sofj8L|Jii6rA+F%1Sm4$E(vAE!p_pTo z-z-<~rdi+}?FwF|1>W1|y5YAT$w?!>x4MG2zyj}7SMUZ|;Qe)s8-917IAi2D;0j*3 z1>PuE@J3kR?H=uh-(5(K8u@+L6};sZco(^XmuG>u{~R~`?nAQD$nR5*;0@N+cdV*C zIy&D=%{31A4%F_VN#YLzdis@hGt-ao?G5?b3dL`7X;guYpxS~3Utp>+CVPi`doddq zI~kk`)=*KFli_9}dv@^7MqeHNVCFEUBBvFG3hMl!m3x1rJ!YmeAUyLm7mD8wS6^ZZ zOUXcfHPnXJ#5;H^#Fze1L9;j!qHo9cICYr5ERkab6f9^CPTCpp2IzDJ%;Mc%7&>z9 zg_AsDI%W_QU4>9PSa4wEc5%lE|2kOSKzt+UUOGw&Jr%r{;N`ublJ@P{g6lSQ{SvO5 z)%6Bk6D#!2T3k=LVBW$RH_uq;nUZ(iO;bu{-7v#5<&t@~c&1!6W8pk!%N%6z(v5%P z#XCG#a2FL@%=6tIf*9jWo&$b{rzW6>w$2Ba`uXQNlilggux`Ukr1lMBv)c{`L zFD5pQd@PW?Vn-#_2bCrd(b& z9RJL?amw^*x85{mdi1)7?MO2{*8esz6K_2buNSGJstwk8e2?Kwp<#yMpAgWPW}lvX z7R$)lCZ_T1`2cyKOhRj%Q`__lsQ`_B^WTK<>ZzDxgjZ${59>7+N9VhjcSLqis?qPB z6lp3jVC_I|x$5gzz{)G;UWO&Xe+GPlSIj-5-D2eiR?KC|#sYWRipiT|qWI)QdL16G zb%;;YhkIdeW(Z3nCS~CD_8GI&LIq7CZy<3bcMzfb&rwKJ%Pwf*vfwG70vDrwttE%y zFWO9#xDKe=ck%mY&{~cIXeDa-0zG`-Kb=@JK@VlCXqtdlaRjC?6kTPU=^ZTC3*UO; zG1Nf3vVr8BDfNRpPcy!2g6$&*=xN3ElyTFppEIwtq$f=q`iH)@yV2M03zWWs$n)s* zwMe^_`q~B;#TiyjU&p6d^_5!QexuaXtZyJxou=-FQ;Mr8%!Cz%;@8L>5(d)ARd9Lj zEp%0fpvj`LQGFnGoyrzn0+mh0EQ8o8o0qLqSt)FQI*4VYv!(b@)7dgy_q5KWzK$!8 ztcU7)`)WrDliSzW_h=@3qmR6CWb~K$id3`T)$S9*%d^4@BTkDSoy4EN&HckZDz+HuTjvJe8Y{daH}L#c zcwRT~QmpW5F!QwA^4mnkAEW$=-N2h>g_rFHUZxdZ6S}T$^IK2F7$d)BZs0Aj!pm_3 zZ;%yU%TO2m?x13hk>4se@XD?5a^1iiVTC7#xZrme6=sb5R=a_>+zKz>4ZJ)nyfDJ5 zZrk%ds-_tEUFQbg8Y{daH}L#ccwRT~QmpW5PIV!_O;nvR%CFcBylGZ=*>2!vTH!Sz zrt7x7)KhiF$Zwe&cnhrXa@@chWQEsqiVJ>sP<6)0Z2BWM2QwYc%^aOw7sn`#&hpms&VGRSewEDZfBvF0u=>d8!C> z@Q*>cm9i($izitSTqNyQoRnBb+SrBu^7thYJ&UQrLvutfi_)_!Y^LW;xP1^Co1WBU z(zAyuFho!K;WAqQ`FJe!w6MhD&{Kj$QzDr!<6nli57nO89y&&#@^M8lp@zw?i3geGH4s?_UhluU zHXHA2>-{;!|0rN$y}#!z-`6QMl#M`I{)UltC8rRY+5hasHt++WvJh`Hj%1}*y!ahu zw!FI=@N)aP^xFCS8WnM9w|Mz?a-aM&xk|u$kcaqR{`_Y3c_lvIy#)UN*%*TI0~*+; zj~b!;x=)URLYbBj=UW)ca0#V-T>Du1wm!zU8U;}p9Snp1Wf&c3B$_)U5kZcVPq5XH zzIAl{n)Q*b>0@0j*25b0(I3Ss+J8Z>j~g|`3@2U>`xaz3iH#Ti3*ydXz38;_Q_0ls zKLc?4NP7P>%0yzDetv&)M4)M`Rr;5O@i}}5gwcL$`z;!_U(na9<=5l*>!>JA>R6+` z9^F2QKAIyx>Tf_9{n(_3>GET4DI^-`VFz;MHZ7&=vZpU>SSYSQ*CX?eft4NxKvHLIZB_uzYCn^{`+l$fyW{yg5^{hGu%XI`$={(fc_r$Z z1Cl9fTlo${waDymW%`EvW!?UOYlX4&4zpTv~yx$2Xg_Med!#`BvorFn#W zQ!mY}M<-pH4*bDl)S=_r>n=q1aqM;CCuVzn0WZT|$Bs+)pmF~NUObMy{#1V2uCv!N zMif(~yFZrJt?cy@1D0aO5>vvPLnHsz;Dm#p+0><=(EL)G)+?f*zs9P|E%Unpimqic}#mM(vOs8!4|K~AE8EnJqYD3SdQau7b0%Y8U0)}vZKGgmx}2@;)~cX zMA83rRc4s}7Ni9;11RYm4j%kl7Nd{9 zEI=Fh9jIxCnBb}7i@2JfNL7BZ6{qV zr(%vVKay{QJ0ZM0E4(m9?TK7$LU{YA_+q4Qof~*-tniB5!1G(-dELNEvBIm#bRoY@ zRLn8TuhS z^;8uy@>}Kx-U2JU95?U=S>d(xal!A76D<5zxq(-1g_r9F-Uur^k?MlqUB_Gat#$)% zxfNc%8+dtEc;VhI_}xcUA)`I7a|3UU6<(1Wcz!E9uN!zNR(LhNT*z+|m3oZwD|Q2K zniXEQ8+e&kcugrT_^qe?lH}Do%;pMo2H^>UF#p8nC9ax!T;jvHkhL@(cnc8uMaSqp~G=s!$wm`!Azz!-S`84>MR~q3j zb`5_4!_VR)v@-a>Eflj*67-6bO}H|h;G!Z;LVi*hUpC{*Vtg5V4w%Ma`cxx_zu#{w z!G!phQ?Vy1ziCG3=h{QJ;b(*aex3>br!)=9o&KrV;)^e@DJG0_>@g;k*EGhbX`|c( zy}vzl8+oM|;IA>k-$2WjUCC<=6>B2;Hp4G)4L^_J$JfU}6Gxw5c99K73H7mqiZKy> z24TG`*XXI-i5mT4d+0X$Sdb9@ajxNKGW_`RN;h%z%)i{pYYi21BJvtxf?i+`-9}z{ z3E}VQw58q#{w^xcBxvuan>f1N9%DlLTEO_U_P#)y#I5Y>ID6e%V&r50`57OU(UyzNcAWL6mUBa=5ZlK5zQH%kfFYxlIeum8LIUiW>;L zkPlEDy_@Dsrt#UyVs>f>#{?HqwurWJ`RYBMOBtx7iT}Y6{foV*T1Dm;o!Txi1P7<# z^5Y>GTHqtW0O`GB=s~bQp%uUVAN~d)u#Hu#I20L2xlhmh71(lQ&fhxYY&mipXee*! z1j(a2#1br+BV$X!Z5h661+-LLFU9qBr89eMiyo{BjBbl(FBdoK?4|IlsJ*PicbdJtfa{*Lm$(x*)eq91 zu61Ki&!8kDHo5eaJ1Gf|!HMI(g&oB=;=6PTD9nLpoWw zJ+@9BhV&vjiNd3ANDVZQC=|0LV0!QfJy3f2$y)}!1fhSam%R@|FYQ>U5_`+1@3!gm z;(;^K^b*E*nqE>L=^4Ff?FjlQ@2GUF1#Pg~ z{O;iH*`VJlH}J}>@N(V28)1bf5HNI`-(6IEG3vM44ZP)6c=>MNa{7fyY%NBYjPuyWqE; z!vcf7l(~VozzQ$N4ZJ~Ccr6H2x~<;~R6E4*ws@G`CNnm%^HZ#`9HjQo~4f!8d@3!%k(Ybi&h?H9wR1l%BD7KTD+ zQc_F2hU^TMj24P}YI*3z6-NR9=X0nHGOhj}* ze|fy6)))It8)i+$lH%I^l(KB0!iz6Vd*Ng8F8-zk@^L@{E;0i7@<~=8A6ttXRvpi6 zVRl~6NRa(=hQBBdel`Z89>V((T7&0%-J1ZL%6HrHE2vZxk8)qaBo*@1jo zJ|8R?5XjFmS@a_xNKs@vQ3Wf;nLf&>6cm+*UJR!wl&{_%Fja4& z{6z4@w2zgj`;eneqCY4z;@8Xb6osw3`r?B!vn6~z+;>r7Nfan6w`$vd8GcPW%TEt~ zUNYeqS>dNA6Mh)g7~1$RELM`cF?QomqHYscQqJU49f3dkaSME(d-%B#_?Je<#O3D8)wG2h~->;+;(vOt(u+i9!%tdGSV!#RhyFcd2*_ffvPFdQ0nLk2M-2 zIKwZb6r=H;SBv*z;IBk|i2OlfN93?QVK~9kox4htc+ij2xXe6fDx7h=f^&W~d7ftMQwbnBPsPEhU9t z4d1FqG)`mcGcQ^Aqd6rP)SW07{vL9|7OM`WJm8P!rI+`r;$KQy{8UB2Q|DNX< zKijt)k1PMoftz_e-r6LYPZYR0!{0iMNN6Y5#YXR$l^1gNM3`7A^J(j=ei z2OP-f2uY)TG@{q6yq5HDbw~f(RHOm@d!Mz?-}?^^=)bIiW!z2r9q2cQ2@H!%L7=G} zfAj|9j^}}F{U2{?-b7U!+H^5U=fsB9d9jA5e4fN($D=cRMfUg(zV1k-QvZAP`u_q> z1G9IK{cWy2#Lho)`1&@AF6o;qPeMMLozi<$gn>PjJ&IXPq0mq9T%3sX1pjy_#jaLY zr8f4=mt@CNht+^hPb5DBm+Ji0P)ypC{8ZIq8~()pmigI_qDo_B7Rbiyo)BMwc5g*J z_N<)vC(ix{czer6-XWgfT1mU*PJ|Uy)S)^tRC|j`0*#e)UM;^RPp%D4@>aZ_I#Kl1 z-lB7hLktn}qEEE5jDb~riNQ^w5OrKU!1U3|Pw+O&vanGK`VD#`6nYoWMSpk<{_$~& zFM0UXAxhW86nZX1gZ|-tfbM4hU=qLWt<=v9y?!QW`q^3x#%oW4oJ?I}fKKhz4m}MN z2pM!;25(8?X|E*aD_X-X3R5=Xo1_OUW4I=A=u-{r7uFG%}Xt+$V^`=e1PH0k}( zE&utE{n6L=cszy5AANhMYD2eE2pZQP)of*1y75N|`zLKY9J-&VfbSRpTM1Xx4-l8b zDolOV5J^m;K19mzQ@#A6(T{z+srie$UesB;qN;KzWuq~KrsB z(4Sad7-dYP0lO5^eCv?3uS6b4V^ThgDs}yXS|5P^&ahx3W;_nosS+!zpzl#`6x|$! z=V;5lA&^E-)yk8*39jTl^Ov{bVeu0DBhG|B!uH7l z?!5rVTd|dUw2~bDJs6@pQTcl3!Qw5TS>0c;I)b8KBOh-7SU7l=p>qdCBr!tTXgRQ) zS|?dTXbCO?RU}N3!;%hM(Es>`I(GqAgqydP&UUH12EE8} z7z#iJBqDSsjh?lnngT(ll!p`@iH&cI#jS7#xa~!+jV;qY7`rG1XZ+%o^76STTCi63($Qkw$hcSE zBPX~m@MIW0ERGK^6c_ZPRY&}D6GD3sA2S`iZ#PBEhM)nzL@1oCWz&KDht?o0#iIKIb zUr?nM@}Tih7GC}w_CePJaXt95k*>N3wx6!>PlI&uKmAp7`1m{F4jQ5qd@e3K_+w)J zQ5}i$kD(%N6#vb{{~wL~KcwfMWUcX!mm~b+8lyh<{8R5G^>4|y!e7uZVhA;9xQ>}n zoZj>=QluF>Io%!Pi+uD{eY_RLWf&0-^S<-@a3NfoVik;LEObK=d@8O%mjDzou z?i4l85}^pvIV8`ZkTepq|K?%7tEitU<}Xl}xnhRA6loNWm||BoKDwTO#%Yi`UY%S@ zc`Vb*L(Oi*c&0`_y*1`|M#|$5szQ-GINJ1eRMZs*d~LykHu1Cf5zYB_(&fkR(PdNn zAwl2Hin>&K>f1Tm*Hm&M{sw$og80uHoV0~y*e|H$SN7-5gYDZ%#`$GICE$z8v|q2n zuPjfFOs`_2fUK9meuQ|8f2*i378Nw^mE)=VVClFNf2RK4BwY%;5j6E7pvjT0RRi3< z5n(I)uB*)et(t#})DvnDXCZ!or}Fw`K2NM)N^!9Vt|l0we}!)e931ER#58jFs=P$7 z!Ngd^ykNq12`eYTtu(SA@ zUrhBBSDil9gCq7b`%=;c4`%l|c;uGM>pc|>+2}hKJq5vqQ%X~|1v|C3JZIsvj1l<9 zbM{ov!6WPV?JT@~3Em!ASGpGezlZ&0DjGm2bvesj+5KsF$B9?4s6Fz)Rv%ms4I}uX zrgtcORQl$+$~xy7`RzI;F;4m|LWg$YjGkge&wp<2GClu6AlQZ8fa$TdkCu8VpEjiE z*hs<^WnNE-w2Z2Uqn2?fT5$}^xDG_=EQ8;QT1FE9=q=++ysa!_CEH^dWkz_4TjacS zvQFG7yPWVy6np>J*uOw*sKd^0MX^@_fFAp1ysfa`MSg0m^aRQxtMO|W#H*>@@n6A?()kr1qm8*s20-PZ3Yj-*0rtIU>(U_UV)h1P(txzX1E z*a&W--(>SQ*W(*nQvkEiXrxy>6^om(-Bp0!mRlmp=&xBE0`sF1Z9%j65A2A0qmt~P zuUXR392}RyFw+6E{Q}A*d&_TK)Ei-RNiN?Zb&djVjqoC~pfc+rUo$K~1P`IX#apPe zMXC-p;%30v{Yf7pI|{1wT;k7Lzq?<>uJbDPXO!ls`;78k6rEM(c}n1YtEAmjX?F7w4Kqo= zG?3d}5d-VHg!MK($m=3lFVtZ*XySi=O%hmy23E0^{`Hg$2=XnX578ryf=PM`7)@|e zD_m0`Z_(~=p#Y;4D)vt=oe&||_`0HT2?!RiVTdFpbF_TPzX&rCSS0liO605&>8wydgQ^Yl|lYyk|zKXw$Hf-q(?!izYP&psW@d@2?n$m+S=`MY9 zYQMr-eBzn2G&@Zx;(r*UU_jHN}c5msHjpD z^JiKifhZ=8*J4k=m(378Jh^8Uu4~lwbX?D!cl{jC^*2oKZcGy|w)_8||DPuTj_;i1 z`#FgE1NzNIAI*}0UpKqYUm>9^V=3<8oAqzV$mvv0IkyJ=X%(+$jDG#5L)lLgwD#+R z1zBPzj8qQTe@V9siV2`Vw3Pl5&qixb-#o4tVyV#ODTv;wJMfF&AzuoYPIrhuCpF(Q zu6GrBP`LfHiuw#}gBR#Wuky9y3l5CjE-LQOl@4DI*Xt4 zsUk)3vzO0n&;`pO`DQ9({5=q9b!pi5z8mNyVr@N;jWR75gyrb1`< z*HKwVKfd`1Dj-p{oVLa&g7Xy#30Fo*GjfJM2l$O#wykugd1vsOz|L$hjgSvc*BJAQ zUm`!t4GZ>|r5UC?QG`+n80nEn_(+q8?E*wQQvWO)v_=g6mQ6Ma=VuNnkKN3i@e`&J ziWU?b?4=40#wf{$C>M}qd!ee45zBCe#m*$0@t19Z-~3=Q?V$!Lj4i)>s$*f{(PsR2NLBC27CFEPeIY+_&Tn<|=V+5<>0OuA9u1#l zN>1o!f_F%Fdl8Xi=}mt?Tt{V0UmN$PC|9=WyEHBJz>hJ&S@Am#5pT!z8g8_06=kUy zk&g#8ph*lsUtO_yi>D+HrCa1fvcx-gksO=k z2)RicpT4+^o)V9rBP&Jk7Vnh;cy}hts{JG$wKvh|9j`U!E&2&EAH{>KS)iS;MUoQW z{|a5($U1Y`mIj>YcP=3`j{Qh%@0R?h&iqLe)n#P=ruFw;aS|#aoM_~3K6Ht(aZJJZ z+d=5T_$iMXE1w(Lk13z=o5RTi_fZ4rfKs>tpe01#km2OVc!Sc_F~Z3LQdlLLkPIht z&`eYe*(PJiHW@?WtwWLPC=`Xr&T+$m85#n|Nz`F!txb6);s`pwitr~@=g#z%O+_mB zuO+BnME%!4Z!xN9OGr|esLyeRZyi@~^uBSb1K4EE&fw<*e(~yb@>E{2;3di26DT4? znfqqGk-5+BwP#M^hkst8_su^26`t!`~n6f4fHDZglR}{?!?e&Vu)R&D88Irsvz&j{~G+Ubh}84W{G@I z7HkqD5qK&es{p)-(T#+x9}C?@JzLbI%^q!l^k|EMcq^&aZS`-?>>~%JV2lUaP@r+( zejM6g6WYEJ{*t7^F9!VB@l+VSh7ogLg*ln=lt977h-G!43-U`;Pv)#Z6%}-J-dVPa zF~FhxH$suplgUuOg-uC=KZctM##ef`52N?;pAzzXecpv9fC|-wx1wS>T;w8T8^I0 zAwiQEelhVDBR<2T(3`Iyoi>R@@NLHU>@-wotnt~Azon-XpPk2P5X5J>QY5Ee%UyDu z_-wv>>2mJ3IX-)aIwhLzXIyck0<;Zx<#g@N+Hj_bzqD3B$MbS1mMXL8y^Q-7CV&#T`^z z>x2~+9z3#!r!=LaHhepf8Xe9ohh#*A>WrRzqQ~Mt4^%L9u{;OzFBqnzVwgfM;(53T zBc1j5v|F}rOE1r_sz%n0=2wMo)O=GPu>`(>o@Gp7s%Z_O_zXP&O%dtDIHCjTLi{t% z%jNEYAdurp<;gP?!OksJir5*w0wYtR?R(^+q%Z9wnrF#pqcFaM4TP{;m3Tl+X`xvp z$Sfa29;^Y2XD~$uS!Wu4@}%nP;Xd`mUq<6jG_yn-(L^l5c;Srx97X?A*GK8kQ1quS zQS@gOiW|}8NO^|}GW_DeQNp0itV-z_`RxOB!} zKC*J8pN}q$@;AI#KI{8L)SikEEycE{W=KI#cpdJ$=J|B?lqf$g=l>!LhW1LMW3dSK zu6#4kcf>O+k;fAzMLDo^(2K^7F&1Ce> z4314bB9G^NWd`uq$mxa7ag)TI;m=|GQr?ID%EIsaG{|w*%{jwYLuDYv?-1hm*tq=C zVkL*To$yN*RkodyUEYeel#;_{4+R~CB7k^{Q*{Qb`ed;!ZaaPnU-h}fE#u294pYEL zD36MXve*Wt6MTzq)8V7J;EeB&7sX;RyeKh?j4!%kxyG*_119GyaTDMVP zL#lKzrhl3Ky^w*-k2Tk(;abZ`MCi{U`k|?_5$n^43YUik=#tpjA+Wq4x4tWH!!Pd6aafH@c$8uwj05Jwp>!XKd{Q%XZqXr5D?1AulG-?xZ=FliIi}8Wtay z&~HspMlfSYCMMe>rQOD}GQ;BMlki)Us2|6l!;g|dVaAx34QXc}gEP?bPBSZ_8fyAC z4Vtp28jPLX8v~!qL$43dxoSu%o8*Jvme2eCZORL;Dsh}>uP!r ztqMYz<4YUb8-Z`Z&Opi>UxvJH3Z$@|Dgpef%!L4$f7|}FiSl8v*Ji}C!M&hNyoIaL zdrRev__7P4bJAaiR$|PEF9eagIqCdXbWZwe0MO4#KM`-MIq6mUj=P^?wX0FE$=(x< ze>i?`L0+8P-RvyUIf317pmHc?06_*7^{B>#=tj)n^rIoBnv49hT?1r!+u|?M@TZBA z`1qHZ@ORvtEc`80t0Dfqq7&f+de&I{uQuVIn>73s$140K@$qjo;qNF-8vj(hA^tN& zr|jlq@o&aIH);5bqWDYV<8LIkKPSqh{pZKEf6sHK_MbHTMH>DAqQp7=j)h6%pUN_-{a+ZD|KVo-lZL-2ioe7; z{*DDn<3AYX{{rXyCk=m56n}|x{2lX?#y^GlO8-9R{3i{6Q51iPbNn4h+9b*UVep{& z|M7A8A8WS%q~R~p@WcPb$3NACzk{N)dytw=?GxMJ`{6$gxCC>48%t;#m zRIO3`k9E#}((o5W@s~Kq-!VIB{8Jf6@qeCk{*#8kD2l(tIsT4WN#nml@t-C-f9ah6 zq~R~p@MnmU`1n_w+FwU;()g!>jnY4opK<(OoeBTkq~R}$;xBQIzvDMaxC8?DJwB{9&`RIQ?7)mjpY|XJZy64PUVyA6BX$ zy-o#l6TY;h;R~Y(6XB0)QH7!nF2{s#)r@4xv&xEZz7^llq~Xif<3sKg{CTYSwoFeJ zf9p`>iO5spTLu?qlIMh^;mg(Illr5Axd~tE^~vI|300j4f6_iT!bO?z%}pA6#2?RWa5CPu?Qe_q_*DOA#g~>e{=%rEMEH~T*#?(m;&0WjlO@k8E57+w zd_$9lFWZXGW5u`S+GO#!4wWC1JeR@cnB+MjY4~!j_y$_>wO*4f{+dwPG4Zz%F2}^* z+@#?vvf>+S#dqN9Wbr3ZxiRtA43}f#@7|>0E3@L8YQ;AoY52TWe0$+?O#H3CDp~TZ zMkOdBPwCH=Sn-WX8onGoKIyMBtoXJ~P8NSPsPshmlm2rxT#iYe*CY*Jz7^kaE544R zWbxO6N{)%YI=CDYe~Xfauh@#O(26fD8Tfdn9uOi89X~&9)T(TJcd{_Z2tc6 zl~SbLKL1kAuc}h`E*Xs7pE0oo6C*Kwc5nNSW_+i*#>eCLY{G~9g;#%Ztd{1b5j6Pu+^#(aIbB({r7eVozTM3o&PWLSh=Nysp(K4&UI zoXyd3hCg4!zX4r_-k$nf@&Ds8DTrj^Z=%W$>1$X7KlHWrc0~;7YcP_35q-Tg)=1`C zIMJ=5!Jx166q!AuuWY85+CRD=y}ULsA;$JUG5PYUrb-aEf4FQt{*V>_Sv`P1Tf@KD zg#QLB{>}a#;GZf%WG_F!pG*E>FCh*|RQv8kGAv>*kNi@5O*X5aS?wiVk=Y~mBB*jh z`YMRfD+%dumDk;c$(L8LhJQOc1HHZM`PkB5_3Z)tf+{zpuYw4E=ue)6l-BTq?!XBl^l^dZDjJ(M9Ry6|&0f!%LE{uNtcKki8sd!heGm z{}nxeKbP@CUyq`*k^Dnn!*15;YXy>P5q+IAT6;~kFRQ+uE$BggRZ(S#-bz{2?p;n|lC%k%oUOyuP0Q8?5;MeQ^))Pn8<- zhv!D{!(O&8RK$?IoQY&z#9lr=+eqfmtoCxLBC|*QVGh#^eTC3D=;hVlDzCRLO1`|- zQRRp1rN0UP9&F5G8gE_D1Nd_oKlBwsuOs<~zK&aapYpVZZG7bIL zWBF1{J)*BNs_YOUpQ3Zn>nmiH*HMa)WVY`xRbI%xuZ`e`y!K#J#>9}kF4smnMCNyA z8p*uCDzAAL_Mp7-HF`IobBO5oTs^&OwUG(Yd$Eb$zE*l)yPyZ@t)|Kk5%L3i3B7*z zd}L`4XDLFGso!i3|6&vV?NwCSy(az91x%*FAEhfYyW@{&4W(Q^Xg#lo z^D%-dGsp*)oX~l&D~F-nh9nYZ+$J~-h4UM>_=^?(TyNL#e}}wKGVlv@4#fZ8k+bid^jD6nX1oi9T6Xmv;2`)2mc%^{O9xHiqRSTb?7WK`cJdMzsxOs z-o8r7=NK#eZ=tq0X5fr|fzCstzn>NUgKpth>EM5tY0>XUxA1dx@V~OcfB!s}@@b+< zj*|b!R`@r$gymzf&Pb#G9xMC@-NLWZ!N1K4f23RZIXd{Wt?=I;<5E6NNQ-Im`G2_k7Wk-&>;DY| zT`)>esHmu@XrrKl_yB`H0bPxj=mv>^j{*w11Qdjz&=Mt$(JbpKC|Inh_^MG+v7${B zY9c8Kh#E8s)=)#Gb}-utl4^Xx|NA|2@9w?(4!gGf{QI$F_TIVYHD}J8IcFYMMZ%w* zDtwOx{-u%d4@(uk(*pn8NcgWHJd~RLGgD;f|0$91uSgYso(2Aqk?{ANnSS!gpHW zza9zyl_4q0r;<4w)BZ=ozamxmc^3G;i-f=DoD}I-2y>bAFN}o$K&tR7EbxC734d^^ z@N+Eiiz4BFfN)Pr_N{?A7o&ZziiAHqRrnqY{7WO@AC@Y7rv?7Gk?>zRYyai*QStQ- zRmo(J{hX%>v0;W*QzUV|lfci5guf3Vo)~S~arlZk8aw@ur4xQdB>eN!1YhoN%+c`O z>K@D_!X}R&4UQ+Mg!3a=FVw)C4CcpoVIpUpnEom*Y_>yk@I40nQp8QH@Q+Lre5V2b zUq9}%!GHaXc(O^J{z@i;AfIsfSEUYL;xl=GU&X7KrZsfs-Hn;utWs)2^e9$WNGN|D z|3R26HvA@=7|I9@26UL8n0H5+-orP0*TLCp54J~=J?xKrb2 zD$_{hCrg#@jl$1ZJ3m#i`PrG17Je3_#?M2{*XZ_n^~WguY`M_ZK0``lw$Bmi;b&E9 z{A^(UhWzwVfBzv0KV$9uRL17#lAougeOglE=Ue7mbo=y*#?O`uZ0(cxo0#o0@1(Tw zlf5t{dvJ1yAJ_NM+Q-gMRcwBqJuxl(3{Q=p@yz$=_L=it6n?ghw6#x8SvL);H1GXSl6>+GF$c&~a(u zXJBglT*CYj+XwTXucPoY*3M5wc}#uV&^ImoOiYcRdCd1{eOro%LFD}Od|UfC?~2LK zx5uW1pGB$h^DOf-nx8+nMd4?xou9d}`8hc~{M4kz&&SNyXny{^Ckj7X{?FDv?Xme8 ze@t51XIEv(W9|HmtBBb?JC8~WKMPXh=ON~PG(WHIio(y9VYc>Zh|SLt z>EUNpYW!?qu153o_b;RHGuF<}5O2)(x#Y;Sv`&&$svAR|BBW=c7A#dGSt>S%VP60 z^k->lpT^Yq*~#pT=BGGN5$r6!(plOQyPf3o?YL6#xxW1p%)PyZcFKmX(Trb ztM4%Xa;ps(H8ANROMLhQ=0Mhbc0Ys2n1_y7a%>6n+d_|%^ccsE5MwV`RV&6n9IC~V z7-MqymNAWE!FMI@YPI4U*%5rmAKqrwpJttnE%29Ytv(QC^EN0WAL@1OvZh3pK7r)` zQq)$|*`MFMuU8=RdIzqrT+>5tg9ZrPx1-Nw@#QP!LI~ctB-+;|_1n5g{d-VEAbUms7_o)>2N%SFPo8csPn5^QkKu>OzecoXL)v1`OE_!QROoo^|gG~%!GW7J0O;P1|oHelJx$c824K#rh#yuofGMCFRpyVm1nrYX%znYoW265 z7gsd7T5?^^S?IG_xvrMkhsi51ZZ3B<$$e>oRvep&+TQ#I-0@Togj6crMAqOd$n<8n zt`zk*Zfv@syUB6~TRYkNs(Sxt`I&u4YW&2rr+WPx(?Gm$uwA6d;&9szq1^`y1#vcF z8In$DzXab_rfK5gEA0@zgzINK#D{U>T0~#@^Z?ayrV9)h?;LV7PU=^ccrv6bFa ze>!@d2EAU4dlvb&bxnfa2M;pjs}QTV(p!QTKaqULF%1Rz{^MgCy+>gfPblBdyBYKz zh18Li-gofgC!)8KX&KP_#&(n5Y5X~*3y+bj!71V+`14DI5#o?PGE?;VB$NIgn9B0A z?5%tD;nGHwUIYN~n7&3k7U61VrwW*!jG^=jP1<25Emk;5{b$++*e?cYTAzg9;X90< zn&0VI{E?X7vq7;iH4UAgK%Z_9_^j(OT~4ok$!A8A=n}8L)$2dupU1_w7`|RoYLy&+ za}(h^u0!~;;E`$nW_9&pF#Zu9@ekhowrb&YFB3rdZE9nN(KY7`rOv$({CNuBx&}dW zUAQ;Zsm?_aI@qRugPEkyrBHUNTTyPk+@D{iP8ZE+bE}Wv<-`ovXX9ZFk|3fkb;d(} z|2!W0T~%)NQt+V@_s-%WzF3V;uU*H$ui!dtpCaGU z81D`FUW}s1ce)5o%XcEmTD~P1Bz-Q(cQXK+@;#kM*d5mx4~g+eltsSJ1Rpw87e0i1 zGe6&B$amCy$oDP`4Ho&XKywD=`}<6*e8-@=Dc^}G|0MEFXn*pUMlxp03t?o%H-l%M z>2>pdZKx!@bT?08m2#HXjZ+cmv z8&&nY=sFwP^EBG{K5KIDa|plY0z3R|orJA)z;8gBsA}@1cK9XfgYO}HN1h%2(dmQl zB>c9KcKB;y^I%BQA)iX5X{yG#?C`HmAN)MR9}?ESKRVJzzd~B3YRn~e`X5Oj{0hRK zd$Aq4Wbi{FPz$XD#Af zX_8MR(neL8Vf0^{KKOZr-yEi&KVoTVn&?+Zt5od@lg}gRgI_`TjbZXRFMaTH2tOyx zzHP(O&NRuV0co15O=113Bz^Ebgx@!8d^tLO@STLeBdq_fg_D^k`BWn9Q?(|{zFnI> z_<4lCEL{KL#HERTg)~pq{IK!mk@Uf@ApD+TDn0;d~GfnXG2>-$``|~5RENOzT z5IU_|6(;{j(g(kS@LR&h2b8jk+IJ!k1l{pK=AfE~fD$U5C6K3Qn&J z**X-myskCA{1$cG7Ep_f9+H2fk;d~m3w(u5zD|hG1k_OsN3&X!FS~z_+V47{MiXn` z-3)}Zd=0A88u{GJ{sq&3Ym6shdu*LLpmi3Oq^2SwoAjXXke53(d40@GOfvG?{h=^S zd5sO1*WZ4}w3W!q(Ldv%>H%n~Z@$Il7N$T)yom}8YT*%#&@^>WXb$LR+Jt72V8VEd zC{z_wKd=|KZQ6t2ohus(k_A=4wIXlG`V`wWB86De3R2%n>Kc*c@DDNY?_Iku41eHH z4A9%~f5;GGdhu5=l|=sEj^H0D%P{Rd%x%vKpmbbcF?I-kVoU>10%RP)e{Yk1 zTaIoM(kSVXPZe`8l#dPm^t8brXTZn8?Wo1yi&z;%7zzI)c zXrXhy##)R|O{~+SVC`zhI^BY`G7Rfqk<>A;E+W?3gIJwGtaoUv*|{OCGoxUA0H7?q z&a_}1j!&(;dMsG2*3XUSv_46i0n3P-T2b_&1{N6e8|(Qk(#>}>1A}ztx1WNzT^PgF zmnh}#n$xNE8mPcE7YD`SsRf8Al9|WhKBxt{R!9+60Dx6Ezd&s?$y4}$1^PV@`rOXk z0_SZS-+;UjzPF;|>uSd*wL+n30A=po`$CY;}GCH2B z^CvpgWaLJy6b*_+QCxU~g7A8V!Q1|i7#s>b4o!N#+g9BfWy^dQ&El4ktw7CzQy+F6 z;6e>Hjuv+Sey>RQr=%19tM5e6zY%HR_`R?L^cP0LFG?r;f5W*BlYh5#!e1H*|GB@X zQ9fry!oM_~@IQp}9VVYIm>Z94WjoNmb0XnO?mb=bdqu)OC7txYx-mjN8?jz7ZSpCM zgkO|0{AyW$I*zF!F7P-LlL)T*P=hd3pX@%aCi=Y`JI_<<1jT?|ndBHkiyXuvV2AN|s4e>E2p z9zr*}A^-}oF1_`@dRJf}%8;5>GJCMP2$aR0_!#54=tDgE^!$gZ8B;!#%J8iIBQk5- zJ6W-oB!e|Me4eQI%$SiCsWSmm;6wb&Z;gL(ABG<7H&u5-*&OX-?H7?2`iRLFm+G<# zA7D*evw9Z29lIXz6Vg}f7qp>($s5;esj}LMY5_tL-g2BRYwjK4M_oy+Jk*QZnjXjE ztF8!|Mc+5l`_Ej5MaWRMW9XEkQEynpb#Bf0(%cuJP@bOJwvnKBr{&dXmDety)AFjT z&O$j%Ue?Vu0UZu`mYJSd@j`@EH`emKJ)F8}tA2)XY7cKV7O+kB9t>oT@zUDHMu{WQ z50X^uAV>Cs=FhRn5WhKpyIXG2Q)eoPaf&EiHSF`R&eV#@~s@WW?BfSTOE3NCNQ+PB%(2Oe$E9Re1mlpK6#H27=( zl7#Xl2fvb89&FCZ!0;{ommI@}U6l|;a`5wF!2j;!L@Xo+Uoiy}h5p~A34TQk_~)h$ zU;M=!!gpoWwlGzNnAt&((~YwQ=iZ~eh3lSRi)TW43BD?1U#7XT254-LtcbuiDLHJ0 zf11!A$z!(1^hez4##baH2<-6JoZ>Gw9US4WZDTSo?qmi13H-ueSYWlE9UmW_WroMq zQ}T<*GU`o%OfLEnQd*8_GJ;F4CbwFTaRg2^0!)W9cbMOjo0mBY3zac4=H|EDs-r-o z&Iv_8qna-OH!J^qC`Z3j`NX{b59r1BEOb zd_9oBV1CrCh9PHzxusMs+leECkEs;WDRNc%GO|9Z_;-AQCD))HReXgFURY{y*@B^j za|rN<*zaQW)_m}?*-AAvw=vKwuIy;}iKS&`s$^tpQP2Q*LP_O%Iu61tJ z{gl0!Q#^&=hWBOEsFE6m?~PXPoX;97@O!=MhYaKOO8kVUgjD<1(JJ?Zy{1=1()E?-B3u-camM=gJ~Z)CRY%3Jh4pH^z`Yx#@tzD730 z^1ceH=zUGr-q%=uC{}n8L#cy7%!!<$u7)Sm1Ij9etB1Lzx%UY=)S@5X2tVE6W=QpYR zy;?^;L4#07-ebd{nKr%@rX#Nci$zCjP!BrtrdzcRG&R7kBdeuG;oGCtC8x0lo7|!! zmH1f}$nw=;JqD&mpye%JhWbAF*Xvs4%U`9wf@|k>J;h>? zOz&1{jag-C%r6_MF;8iYXHS} zzFw;&Kj}n%ay1eWUe~6wl1+{|gM4lKdR5>Ro-fC9pTk>z4Ukz7^%O*WxN`&$A^q8j zn(1?G0@O-@nvJi2$*?)t!52FpfdG82t^HlYeEH2sIj`sdaHKdz`{aK{gWxS>t=(Tf4ik4tUQ7_jfl z)N$YK0+%bbqbzd0fYhPUbD&q+fS30QAM{ zvOqRFMQY+x|d&?UD!6*NEUHAC%?@?F5H}tv| zu=qY33Qxt7-(&X6^_XV+TnoJAJ%P>AtmnN!k@4ZqB6P%^JhMfMgG-xWuKd%{*Oc$y zS{etTBBc?uX8uupea$yG8%YMitOAcm%l5$KB3sJJY0Byc&`tZ(KQr{8L^MlkP_9zT6zw#+dQ#b2z7CQ|3V-sdT8*+RkV;ppv#z6cP1WK$O|2d4usyf<5P1?z4^5( z9jifYHl9yK`FWJlkdEt7UWPKq-D^>%WN1&vp-fq_&S;d`7<@hoI7lcsTQZi~lqnx+d|-wd{@6eSsl?|AY<$#dl~i3_}{o(~h6&42g1N zddu5ki(nQzm#t;V(f!WFcrA5&em+ruV&1i!V}#r1Uw}UahOG$DiWQCEnk8juLw_S{Ho8()p`FsIyiQYi=mu0M6g||NW*IT|C<<@TX@)yV* zK0lv${h8n&A9nIBWr<^ADCRo!4+8W6KOK3d7(D8SSL9JAMn_*lNERccw(ZTnky+xU ze*q5*PhrgfACNO(oz?0J`3!0^P*tKFG(Y21Ijjms4^-AVQv5n}WGXCNbR#r(CDmmV z+7Ie-J8{7XEpV`H=Hp8ZvBnRJP!fy$Ke?)rVJ5Bh^g<0vZu1gF3mCVy1Z+Y00rjL4{ zOl@1cYhR$Y#iez|$i zzA7L&UtqHqVBZiIc3gOq2=ChB&0VbUewG;C4ox3U1Z=MEin3LHlFxPmF!l55rx>{m zz;Yo#skgSMU*1o1-4|^5Wv`OkFSnujI3>iJr2?Lr^PYo`|V?7!)d2aF%{WS`X=fT*}rxoq)?p`lAz8`ZNyYxv5R|M zZQjCm^*!Y0b?xvLs=+n&uBHVKE^}Z~Ra(-<(wwnnCGCzm1$Yshaj1?kHf?nC^?qxpO%{?EEeMLI1*wHkpg~Tsz$A z?iOx3@;EmBE_bwBy^C-(f?3`|Bp$;m4p?ff_%td))(B0v72vxOfPy%Nx3CgHug(l; zR2`OIsiSUQf29z}2pkCHpshBR8U)@;cga{GLIFZKroGuQ;fLu;GCxJ1S|ASeM}J96 zHT`)*-F0Ifjg*oakGY(;ydPTAyObWFU&_#IPGr=o?FI{vAj)L2K$u{m5)NXA^(S8b zM(kGw(?QVhcX7Ifs*1Y8X5+R5RnhbTbjX`M|9%KZZ4^ee~rFw{sPKB2qV6)%LT+ z=@wynphLkv2?$GKzDivRN73tA3AI*lA%cW#y!IKZ%t`BOYxs1fb^zzr!2$HZ^^EQS z-u46?KttPQCM@Hp5vN;#k4+zN70Mq#**F$GhjP79ehTG?X=GTN{ggkoKIA@NnUCym zy#EzsVXX1~-8-~Sgva~$J`|=C&l)#4Q2uY~g{gB|KOVN~$K0U3 z7zQP-J`JsBIv8>7#RDHuKNunFE%C<{^SLGr0!Ac+hsdiALdHORQ?EWmGzJ-G)z z%L2U-iNivjPS~-@7@VudI})kAI`2s40KFr#5$5!cM3C98TYWIE@RrX91fQS(dh?g~ z@|UQO;IesL6)ax%EVXEfwmC~on==v_BA=^5+nhiHbgK=vDY|ZTew4a(rygOu@==x3uMlqGHWoeOK&K@aQqcIsWBW!8;y1R#0mUG*<6u5 zY!hZf_*=Y3)CwOv_@Yh)I9lWH-g_ikn&DZ5SL(fmMyTK(;DRyhRJN8SNAZdB-sk5p zwHhm&U@Y|y?<3UEHQ(uwFaHvWPoBW4X*d}^KTF>Hs(RN-zQ^a7^sc#GW@c6DBT!S} zda~ZNgfC%LpJXog9RxQ#W3k25?`K9!wPP*{qB_&LpNokz{QR<#m56_rV6?=jTUL|d zbuICiv$ETB&y0ycvQnLhnRWNq8p<~yIgEM+tRwNgi~!xsPr%cnEWiI6;`qfz2u!0p zo(8yl0qFM2zZe>_xL~CiPmmF9R;Qz9h>7<;?ZGp6In8R?yR1%7@IM~r%AmelIv_mL zU!I40@Q|9-o-GiE2+8NC&gE(&A-hHh{=<3(7dgFm$r>2juL0yIq zDQJVH8$m*AmehpC48lvcz{pBzft~YcoFb-Kmt(H2b?VoM!Ap2&AXos@1IpI26w)dF zQWKxnIwe2Ol9)*>of@X$ApgLUH-9CX-tB3AP&fAyq!=~gPA1~s`hx?@*0K~r%wOss zu%A?B`LPDUlGw`JPs0IXmY~d-N4h-$L0qLSN8iB%?fR`WUB8Qwa`MBmEbjvm`~3V@ zefK`GWQQL76;lXrIg=uYAj=D`Dc3dR-&}cFJVw9N86cnJfp`+Z(snjMH&r|j6f~$J z1fCITs8Vaa_-)iOD%qB!KMyCg^*&mGo6sB3`Opy@WhI!%+_{h|9b8%7a%PN*GW~uG zj{8&{WaTes(e3l|jhZDY#&Cf7WIVzKtp^z&+$wWH2^T;q1;*xqItBZED$71a={!@p`G#EhQEC+LYibqA5E7vas$u4q23cwTfv z(fBo}ifUcU*0K~*JpNKQKcN**eq10)v{)M7py4Y|)| z?-m==O@FKgVA=z?PK{h0jh~U7={s!IFtp=@&SI=|K*=Y8OZ9}LEyY>V5AOOS^=1)N zi2aH$q+f;Hsa$!GEc*SrDQ2WVH@C!+7gCEyDk`5L*3EDAzZ?MMXE!x_ zHZV4*sZe{NdQBNAke5!Ql1)*cgCo~^-_DJ245*K9ZlJ0*frxZX2$`eet=Gg#*H*^I#G`Rsx(to}Z5Np^JY z0JKZ>AAliI{B6Y?Y^pj8?y8526A&*eZ^5Tnvkn14#fxyngTK5&9^I!O)tAr5PyVmI zd?rdjg7My2HW!0`Ii2vwJzQW@bD-N(@jM0=H{hz@{F(}}6&i0wLe}z!qxf*-0t$S7 z{!ru5Q@rIXQDjb*e+BkZmb^=M;9sM`fzIdWZ*N`}7e{*T)-?F=v(SmXRhMS@7EOn+ z<;cW+a6NPe#p$~wOTB?vM^P7o$jefv)*+9|RTs(dO*_$Gk(4 zLc`yY*=`ISKv$r$vHVud9ce;O$G_@yz;Jt}{~ElKVEb_J?9{rws~NiePxwdC zb^8ae=r(i#y4{J)%cPuKw&P1u$F}aZ?MjCl`=DzVUw}x|cXGB=c#m zu+bV{427&d0lb(RA6yb}7MxmS%D7?k0JMp0rDxuZ3jsV8dg0}G^Z;atJxZKcsapW6 zAaw(7PmQj%bFOrXvXTH)Js+rxveoaA9iT?w{673A3rN@aM)r|KM&&} zwWJ)sLIo>tdYi+uk8?qB6~LV#fLQ|II{Z;n1n@i!7^25&3<`S=H{~CK+R_^H3q0dA z%0oqj2%iVEey{ly`h76eeH_={1(#8s1B^7&h-cG|)}dAd8l5({5oIxoiPh#mRwH4& zM^dHB;2ARC+xZSNR2XGF(E2Csfu>Veh$LbJnhXy0`0!6_Jcx3W-cquUp#0XpH2C%<)Y&1<3UAIO)wk2q?u2jvr)&I znNQcx>eS0`^O{|y{xsiIA|t2%1Ta|k!m#rrRpnL-4ref#UWhpy>kU<$G9z{I!Dw~a zH$S2VGw5{0jD-3c`M%k$98O!P`TRPxUinJC_48lGH{khx3pdV4sNZrgIS5avPr*s=`Sx8uxO zAD*}B!~U+XxE@}JsSmHN59xz-eZ?Ps6{ZVM+I2xUwX5E(21_=y676PJ2DY|VhFiX) zGCYOf7Ghk9I~J~ZP~Qy;QE59z}JD4T0594P+}=tF6s1_Z+*N30ht zg}Vp~X6}xIr{NCU{>-&gu;~L0DswvMsET|D zLyv%w=he!1>;z?WPbw5@$_2MtR{R;Z$m*G8@x&F;OuGM{_gl+&u;22#4w;~!{1$*T z^*mh7;GpSLuVM}mLw>v9Sh1CV8u>L~ZZGoNWtSg+hRN?ngOKRz7EOMofq3mF>sRwM ze(ktJy>Req8$1||K)o+TB2o1ywszTh0z4JjkHTR!*pVC6ZaBI=@x%1M7zkis+>PEH zePDE8)DI4f2k=|5=kS^wZTPa$@P{1#{AqpPh|U}3K|=kP^M2-{1=+uxI06_0q8E1; z@~>4*kA=?|TTO$Qlf&msjPIrU(}PdX|5gfr!Bf&O^6WrksW+~(_r-HH(wL)v66+TP zUyjD-tDr%~M6BJnQ1I<3wBy?d-z&a}6nVz8$AYhlD<%>1U55#PB+ZMn`17hs(E16j z*RtFNaRRY#hcj2lGo}OFtbr2`C7Kd2^P%T}q}G!>ZBS-@w&V>Bd1?@HH$HX{a+fNe z{U=Idcn#m7eVG1Oa{ZMP*v^OviIoOw(HVFSLp z;6@<_{RD?r9inM-Bc;r70|Qk+t(O=_HWCOKia75wft-W5az-61WrM6NSkWeBl4kDRJ-xe45vIu6IIw!r#_N`*vRv zz@b;k!Jium|MYai?;Q!BE7=lt?xg9jV*bUhXfrwhpWRo_S0nf9ol1QlNB9`_KEgPl zx9J&s^Z2kFkrB7L^hw?MaQzCc1^m-?^-H)HCRv7w*b1jI3ATe4LE0~5(IV&5LSGe- zbEX=+`vu77UlBrX49{05MxLC$g(-3^j!v`=!34vr$+a0Yy9s7f-Tixxs(VA?M`lWmWRz_3kd#P zgO4>OhztL?aQHjWC&S>^my4YC3w|x*cgDd%>J<2-VX&vghfS@v>W{y~cHBU<$mm+Z zfuU|8Mo)Baq$QC5V4)~e-FTJY^p+3d#2R;wsdLczXattZ6Nguy&~514C&(H>y<_nj z>Sdu)Li*OqLNw4fV!A=!p_s%O^wlGV0GU|mnfTT_Bip3q z$Axk<&FT^@Kd-Bun_$$r=Ffni#&WXPuOwbI+ow>zJSok&C>0n*6M+?iJ2YK0GYpryGVnh}q=l zd!YqCH9wj({7jOc(dt;u407O|U8{r{k^yF(raj*;W=#E#$4?1HE#c>S?e3fWj4^*| zeq83yr1`lV5p*<8BtIXP{*?T1Ba!g)F$Q}}`)o9SYJT1@e zL*`D~<0#{mOanGUr35J}plA5*NQgAn_$2U3!{Ftn2yajryw=-Oqi;J@&dTq@Nx?%r zV3#!>U`P|%HF$$znj=C1)gq5ufRE8{r`*7b{ie=bS61;+5~=8o_yAG*1Q-L|S0xD-dQbqHTa5&&6B9_*^E5I7rR?mC0p0 zZ$43{VxkL1F(&!)GT}rcl7VJW?PBS~TTnWrv(r~Q z_0dMtD3Vw6h<>=g52XJl zZ0{T+F26e{^KOiwL~rkx{?8QZ-=9P&qP_2=G$EU(Z0$XdU&U+hIYHd_60E(wd!nD1 z?M7qaqRgO~{XDQFML| zonbN{{7n6&`LkX1%wy9IfF?xYXTB?fADG@Se%2yMBjsS@h~oc&?C9};c& z=3A~flWTW;a-bh<4^W=N#>mry!w9E}f{OHc}Fk;SgRFe91Ubov5f%Jvbs*VA<)# z!rLkxR^s{wwF84{>kv&o_F^g$lfF z?FW3RzsO&LZABE1AlL`lhPVs&N+;@x^fj}A4IL(Wq-=jjg!F!g{t10{r$wK+yN1%A zcVSZcT>EWj*{h6IwROJi{yl2H>+Hn^Q2;OlL$=o8KMZDrh3W8Kga|D-2ir#Y4(OjS!F*_66Vgl`1>s?A!N~p#s!3%74MOEV; zIgDD=*hX@g7H>w~Xj*(Q%wU)nH{57wu>;fhs>8CA)8gYUCLoi&%-R@wyoCPS|EM0z z_)-G{i19Ka-rR#ZDXikxYbIC=!`OO^Dc~kXP&6*QT4-7Xyj%Al-YwDKowWb(j*ABG zBTS+8li$ru*C5dI+pF#K;Ih~tf*v16b;_zHznkkxk2bl*m0rN zBj{RfW1hy9-QVS`ZSRcWBu=x;>3%Oa9m3(lSSn8gm}_iCsJI1TF zCCpC$%xG6#wowVMvUDXLs2`~PTW1WW{oit{M{U)(kwm}D#!JAi-QL+(nB9N#Xf?-H zF%W#AgK{Qnb(yZ#dW3;Ev^7Ny)~{q{Ln)v?yf!_aygEAC#BHxq=5}0MDn-Y|yiT-6 z({Wl-bi{>!Ts-*iPD_SQf!_{_L_Zp;xv|S0#PYg+(3LRQ`H{2J9z#sR55 zSDUzPxICvVHy^J)kymYAY#MU4xz!>pX@XCV>5Dtln=cn(z;oAkPGpZ(C!?!j(9w&^ zhRC{6K*fF|>?bX3ll?_%^CYRmL*Ud13pf(Mm4vM~h%33N^#GpQM!cKK6rgPKMaM8_>dU|&lO8*G}f%KoI>Vr^>(SK$$&jbr-SX%a+ z%}B+mvJ&OE{W7Y)!tq7WUTDA5-?MhK8dD$wv-BNUIBa9ag)M4`euw!7dx?VKgaJPG z9DdNV)!2-ccLW5m5K~}_iawQ3k&$Ak=yPzRsG@pbog39n9lZwSbm(X-`z2$~BxZJC z4VZiJ7xo;jjv7n)4Qqfi81*Zaf2rt;Hv8GS>Ml_xqiU}CN*!-jwLtx|wQ30JHy{#rEuI2qTpI?w6PI%<{io@1duzo(jj-#Yzx5Z;TLsMcp;cynFZv(M9D zn|0^-Kt?YE8V;V8D>VejkyaqhBFW~~H@Ihk`*snKsbhjlM`G}xk+41Zi#`e}*hg=( zz%I^geZTc$jk;0bzdqO?60Zif4iM@ZIouKgCYisHkpYco;s!Rec(>je!l4_{AV>>4 zLhgj2((vmF)T01SRTDbC9L*nw0my9qb1RN}z^2$=8FfsloopfK+}6Q>r6q?+c!A2- zm4~`i@e%U%Fw58KBRx#*yiw-Bb#Q#<^wlDn)0@|nV8D{R@ZqP5TJEeBTBV-LU>vHT zWe>@c+z{iYOw~;D1-8t9bA=aDXl$KfAOo;EAzJp!&?+dziE;~7F~HOEgOgKCD9uu{ znZo8RR;q`7(F!dH0;$8R#?k6)47Ng&fpBLAcCF}fcfqk3IozEtk{HKL>vy}q} zGM?EIc=6_MM~hE}H9GC+GO}SV8-4^Gixy1Ua$PMYH{!2Sd2ay5NCw*KBJbZ&y&t4&InNX<~Y4s>%C*vV{vA{>&j|fjK4rP zX9UduiBOUS^Sb1fHS8UZlTuE@BNMN>BQ_jT4p1<#y`j}T3sk3Zf)h>-3D!5*sRuAf z!^sijZ_Mfb#t2c&7)L6)7OOqQe|dbabbL6z=o;bUbBK#!;?*!zoYlY3iLl>joT9~{ zb0!Rj$w>`568cr|4ss&&HQ`(FKLgcRh7!yF+;bbL&FU}yXIXov`4{1rSc@#mR(-CW zcEj7;rAIn?o4X3sM*WT~gc`y-UdY!LWAzCz0>@lovlv4zpv53{;OzgHKn?nuYfya` z>;&gS4JhxguNkX-#NWygj-A3IEU(R9c&UPycs=GLk9in#K9oEasm&Qf#)>OWjVY_qYtWqAo`hzoy&34en`0HVQH znAOMQF&2F3zuSx9uEN-bdO@gj94=EWSrtZ4{VKTb^wi(CGB+&&au^=LpIraE0@Q#O zlZ3u^9BFu(44;97{xY@6+F6a(Ei1`(+;O`7eLg00qEe!5#z$u$jf96g=||bB`(3-- zYLbNf;YDQAzs;`wwo~U?FKo4Im!<;j_s?%b;v%=U)lF-x;jx&Pr%2G`E@b5yG-*~JF)YDOa?v14i^&$u)O#R& zBCf1lg*RGVieM4i$y@#dd@!H<3(MQATrg8cD$+0a=cy*Rs5r4_`!6rWAOfE;)7Qr1 z-B9<86OkhJU!<7twyc^ya`mwh# zyWZ7;ww0ayEs}3L2RS7)<^wxDd=R(oY zHDoz@@WZAkABLWxZdpl_W6rw(DW=$1tkHr2F?Oq26e2-U+Bf=o?ofQ7zI+#YDJ7s~ z`Vdk&epicIl}j(iY6h$-F_sh;HjP$)KT3CQSA*Y=L$`5W=yB|+t|o}PL8g%JP67E# z3AJovhF1z;Pq!g`o*RdPc2wi%y5yL0nkmpUQ$g>rlG}JvI&)id`dxqrM z4O7&_@;vHvQ=XUfiz3fucxaVp%RtEUM|k(q<(YN1MV^Pct@2d((v)W#%ITNqTB|&N zF!i&lx;u*D*^CJNe0Zv{BgBR1FMJxruw)0)+2+q?9O<6lpx()$+&L3M2p_+%u}c}Q z3`PQkzf`WP87Imz1iDbNg9!Mc`qz+W>sFRd#t^0*rJ(vYsO-rUH@zpVzV0(1?t3qc zCGJPgq_~~hWqA^wDAm`<8;!%KJd-jD+)qY1o$?O1i&~!#{+-1>bX5LF!NHUrIrnR6 znes0)e0j_*;+C;$UHODR@o^3 zlx@Yfi#0yTHiyNCOu?U#seGxPBHale8ZlPutnn;^{%}>0-*Mp&iiH13{|NXW{zA*A zL-55P-b^nL+>YwOGJbKn5^d|H? znQNnGiTN{(p3|e!GonNE)M)uw*Eh<1V-S;0Vfv52bUa35>A%3+&g6?7-m+BSEslhj zmkPWQk?`8#K<+ocyP-p2{8pv{@9{`@|V*r}q^~IA>Q29|1{fI};S|(%|zWV?j)1asEh;Vu?!N`o4(T^p#FrDwD8XiH{AmhRt6b7$#L_!kd!rKlnoWn?#diiKOrHf-h7I+EwH&p;|#D1+7 zt`^SDEy&{J4%vfqfJ1Zw8?siPkLkiO^0;sCG50`mx7MN17KGG9l18|1_i*7n*7sle+pu7CjHxTg7jY&d~DKx{J;qM2c<-R40|OA>AIhH;Oyn;x0&Q#!KM8c~=P$C}Z zap`**0q`(>J*mK(6bY|)D)4$l!fQZkX21EZWh%$szH?K7cS|I^oK)Z)7YT1Gf}H!! z@8&Bb_^n69opSyqj%CT;{ znIy9FTbT;H$2C0UV6CHkVLXs=?MngSVO_Xb?XJFTx%lb;fU|=C8skgs7LNsA#)jQY zrodN|4D?dWRKp@u561;9gDBu5{(h}BUfF^D1ebEum##oI&L#L^hKRY;NH(e-Cca}&$ulaQQy<815d*|;9V26~d6_CVXdt%Stac(cZ$vAt z@c0d1e-Dq`tzJhA7|XBt;0r$R9ZWLR*u&*pfRZfuCkWT+kn)N=1SxYdzl|QjzZA3t zHzT-*=vHD*t`gswIq=meUpFU}j9kc^Fk`^^EQ$>YBTJVw9m8F_E|3NqZj94 zkCrS2lQxTcrwqF(jZ&@nv7DvL%O9kGDNO`knboj~|68^ABU}N3Pe;wQgkxkRPWo`2DW0WH8_{ zj#$SUFn@AqabLIU`n9~SC_h{aj(@P;u%$n?2xHwe&T4^83KXdAKPSj+Q$)it{f7Ke z8AEnYH3&arh^Pv4@p$cT$|2dmVqX%j?-cKAHgiG@e3TqP;`QQPZ$1}VO91T#%VX4& zOtwYEKY&)<&EMAJ%!3Q zauj?ExCP!3qc8^MI7Nawtt_{ht!3ulQH&50GSfpu?|gnfQ=Kux^p-0WIq>l>Xma?L zvgBRrgvwBheB~_RyR9m476!)yE??tPz;+0OjU;f3%i0!-nMH_(SOYkqb(K>4k1Y38!P09ZXa)Q404!C+$ za_&XyiOOvNh-9^6Fh4ZP15ln&I7;>+6<(CSy+|F9=WL{cg7RE;PDq~XFeX{#x!U|0 zl4t*eE%Lnml&JFDQpm?q2X*_3A)KQ!by zALXA+o<@8#>UolK-d_&0Ox!a8V<>-}-aPC>vc)*xg_zjK;-5w&?UxW=6*D*q@cl9^ z_{`}!Umr3zo4$5_F94mjATF&Hb%fvbKv7X@OD zk5X2!lx>tG%)!QhiR`W^iE(UA(7Gk!SJTtZ#0%&-cmL_RgFXd}Ob~PQLPC1Pw0cO7 z?D>hUzlUgq2~r%%;cI6)Cjq`k;Zjkx;vcA=9KMPe_}F3d*ki3NeWHOlen&OLog98= zNAN#=l4d+D`03zL)9z{e%8#`otnmmfrz;;>ve3{IE3gD_JA3HW;2>AZ=z}MksD#ojDtiyOX*}xG~P|4DN zH)aH3u-}2pm{122!w=Cv5R=m|98(P(`%S;@Pve*sf`oo|kZ=)yytLZRop9s8W9(5W z5q}#0R%U5{|HzKwpPDj$84t%1zg@e#CxWa8goOMFe90Qw;lI>3f#f;@e;HFgcKDa4 z6aJ7$_+K8IJpD!l3;uNE{ZrykZyjpCPpC&X0Ea$IfO@~8wa7OieM7?NdkWD4(s$9nzY5ZKTvvm>7dbg-P_yYk+Ua`(8Jf7g z#Y$O_KEwlmw8l3=vxUU>Wmlic;Kn>AgK)cFm(RZnWjyF71XM9>q7hWUy3X*Rm9d($ zv!*+NYZgg7o}hm)U$@*6&ouIN&<5K9U}k(K6w$(_V>pLF8!T*QL*{cN|GBL=P2=i5-`!&dr&kzLye+2?4wV-Mgl^wNB+ z`*+_*Ed9IV{Cqsv&d-JPYC!sm)(}74;lc|)N5$o59HM%u^t?plxmF6jq|J$i7a&P4 z-y5wWe6x3Y3n}rf=KkVa7m4rMwBXb1%;$v3?ojN-vV_Ev)%x(LRUbNH?_pWdpB&XL zs`*JZa#QUm|q@U_4Q%enB>SIsPX!A=#C<15xZ4c z%}lp?<44-ftl*=$ZdIutp~m{*^RdJ=uzp0bqsXoP^`+g!b}@&jenoC$JW|b6rGWW! zR(PYt`*1v=Syr^S#zmVPf1X(QPRBqPhVOus@NrbF2R17Qt2qykF=c?zjcgK#p5?*A?^1I1^49t;LUH-k>nSdYszm^4z>#Z zo(H8z+NxCzLyD%pybp$c+9|)3U?khr32^$*U+|q|#PVAUR6%F?q0?J|n~_!d`+>G} z%)W2FLOOqf60wIfkb`m0nlX3Ygh|t<&$xb4@r+riS`umh4#?wC z=8C}O9whnrclAH$GC&^pe-B?bnmoE=GUQeV;=7_VcSN4bLpL}K0w=o8R(X27#i}_fKb$kv%PhvhP^Rbg< z>K*XqU5KO8eHmCXdg+Bew_Yx~h0#boIXmnF3_cjYPsxE|nW{(U=fDs@yA6J>Lid5LMdRn=LsI7_iTO$;b2Gttik_Z) zkEt-VVFw0vtM$1kE=h^(tzP;!MC0SxO}#iyVVDA@Coni6&{6t#yZU_yOO$k*3Vvff zfJ6i=3j)j;5LN`x{>jwmMJ8*|&rieDfPZ)GkpBLu`nvHeWVb)X;RBWvy>(U}^$OI_ z@F6?A97^hjO$>JUz-)B*9WViwMJ#*2Vuv@}q)dY$+PpSY{?xR8#bX`)t{8M?DmJgf z{4;R_z87J7$G;_iHTeG$?s;7P@nML6@lFkc7XTY-2PW}W{xOpb@t>s|RQN~bApdiO z|5VsdoL|!Ok*P52R;9j$F~DecL)(Ml`)vT(L!daia3chf-87Iv3H6$8ti7##DsWi~S%`e`fE+DT%Tr%Q}C( zisacRd0tS{v$HY>$R}Xd$vCB;hM8T z=RNc|0Ovg{zyte@wznZ-WjP-~YB|ovXL6&h;~e{W50{{}aXv!%G?x=cV+1-I+boR{ z=;x>bp~vSkfxJTzj~Maob_O&;^OtU_1@=Xx(T)wE!5bpIg)L%TaWyHmE$cT}dFanv zEQ(JYaK`2`&(r}O5q(HV-?(u4ev3%)e$lrTj%0`F3ys*3@j1y4R52NY5vMK83=}2A zmZ(2yuX>yT|1%^ItY)TL>hNXhd^?jdXn%b%64^ylz5pLHp{U}vpM8EHJ?&m#;sH7> z>PLx_wZR!~Q3X&pri)pA1RBJ{;<&cH@oyM3@$BmN`Q8{09KXhR&;<9{G9LU3!)vEP$3iJds}e2*f2Kiy!o?5h_CilQ`z8sN-lPZm zc{6-4eU(fX6nD1p4#uGFBJm+vCB6f(kW0@jO0XqO~#2@VW*|d=( zo%Ma}v z>H+vz@F9#%A9En^euj`+aU`Sjgi=Jy3ULt}p9;xD1c9%k!@6`@ zo)kkhwP|nfJVGw~9T~pb<$`qM&#~aY>7$5|^8+}OY2ud}ba9LH&a#$_;zJN6#MvvV z>wD4?C|k|d)rs*Yk}vT+OCJ*_X$n4^>;ilby&DZ*E1bpzd?thMQIf6k_3-qCmnkSu zii&b>0+fP}xeaYUYzL5r{1FfHOW-sIo;`;-6nA2pq|dD1jQej|`Zo;C58T=X3;tVi zc|>5d>daH-aja%jF1!^ycedg>G258{+Z+j{5$Q)HM{gCgG$8V73>gN!Zy*<%8oj6P zH@%F}Yx&k$kLU}@*GYOq=NDk9HXIwo%5lF0M2G@T+G~J~Q++?9YPWD=ISk^ID@Dyq za=X$0WVIISwX2xGnHAdD^BUBf(iw3&0=6tnb7f_9=Kj?tZ^krNwk|h#Go+W0Y*?eS zAi4cEpweE6`DYd?DgH448~mRW&i{j);%ff&ZJpeHVobg7f+Ys)BapD=L$Z$X9e;6# zJK*rZ1&ks3SA$ny(_^rIHs-$j&3?l9nx3UQnTmqGj>fD421_qtQe7|$2n#Mhi-{$+xzJc!bze;Y9f26{m}*{X6*3qNGE(x zB>ZF33EvqB|4lfQXz7&Y(@*?Arh4r1nUGHSd6DqzDz*Q?(ub@6rUn!hruOTm!3+&P@~i90UIE;elA;{{?xX6y+oH zn+9fZARm9N9saM<1m9!8Kj<|({3Fu@-)X?FdB+a_b^0rDJ3&JI(epn^%CxInq4ZYy zUzIw1t^b6Ndx}&iv;sCzlzowL!dq5EySd#VnHgP`mmo z+6b=XWk@7gIqaSs#^m^GX9mUCneq$bZct|->fYKQBUTo{hOjoBB*#_hw#M-Q2p4Pkw8D z%4v&)>7uTUh0DRiU}s)Q{Mm>f6QA zh5W?n`Z8sA?O1rz=E6p{;GesPBr08GvMJy?!`jLRR+8_*9r-|*pO&02*-Pd^+UB- z*A{}gybGvj8>sQ|0j#@=VDg(#a`+B`Sa3RDn+p6>e&;v(dsd8A`w;3OwRrIXUT|W0 z41XLhUkM#=@B=4~>1kEVI8VddN=H^pto21oSo5Tawmqjn_eT(ZxKSI zFC#{736Z`Hg(|J1YGRJL8I)^nHqLY(fG^B-6GKp*Fk<>mlTzOO9vM&gPe18sfBYBI zEf8|ndZRzS&3=yu-dClybbp+W9|`;8SXPSCA8)RY=#O{&1yx@Wz%jo^_C~G~6qMJM@P#Km_LjCbY zsh|UGF{u+9|s$#QTGPc z6}B5+LCMk|NAV3-JnH`FepyqCPX^;fus{AzzLNfUl%SRVcowJUsOsb+vp>#2)dc-< z^#kaS$03$v>5sV|So-4#c5oS8jQ+R=Uzq)|0p$c0AFJ`GIRpnZ=8 zo-p{gr31dlfPdhJl#dRNn);s(_)Y`Pt)V!)MrsTq%#NLvbQpFH{OOcDGvhT|KxTowIUfbIyUtqXMJD*H+XS2M+G*70A5afh_O>IGe0Fum*n}u&HuidLzfvk(?$txy`>2 zGX`A$?VJT~9rxnY%|2LOmDOf?^BY@x%a3}_Ymi~%Cxwl^5t-gjt*`mo1Xo)Z!POJE zjH7QJ#<;rS6Wh4@85%2i+2T&D{ew1O^^7sD_QV(F8HRmPo-k_0_0#q%Q=ObAEBerZ z_PUwLAIR}9FXFHGFS9>Jse|pcoL|RnuSR2zR%TvjOvwEHpMqg@mJ2 z$rJLJ_Ql?hN1?vfi{?k67a4H&qMsa_-9QyFmizwz%9)Z?A z#-j%0nCrm_2L-HzXu#q_Z+7cSQGX+4+&Rc{uwNxxkp7pDpRG*3{O9-?{HfW5$+8iw zm(ZT{V}8+b;Kb8PQfKQKD?9vHmQcy%c=QU>}JjCcY8r#g~%^-{x&; z<*$l)n|S<9>JYwo>kDN)Umo%0JJq9&#(KUvXY*%QSX!?vCnPa#Zl9lv41GO}znx^g z-bc+`gMdM66`Ta=MaHtjwRl0pk<79~tG>Zr4t&hAza_LgD(d+OURKHb2XNg zG&*h_56@AqSZ?IInHW;Uk1QLu*ioEYl*xxz^C1I3J_Ka>;2|nsgL({pB!A|b?im2wImgor*>f0wD1QWxQ^VYX1=9|#2KU)rE=dKv~j zdvh#G5%9%I$qun-+HS3jKHaDx)d7utK|@9_tia?SVB-uawz2iqI3 zg6)0xV}zsIo1ZX5|EW5j^Kn3#ino^b#=OJY-fNygd-uiapXdYl>2F%v`z$*AW_#D+ zL$kdbQU33=_bO|9hek`=1-RyJC~M~qXlL;uS>BEHi5&K2c*i)80+!ohbVmVcpfy-W zr(S*otiuC9XXNey^G%a>e1_m`H`o#6Z=mftO~iiZ5K7|$-hf2`v>kza7Ro-AmD zY`0Y6U4y!xwzk8fD~Dg2Hqj;YUt~U%$MhA3u=`)&SQflW9;?(_5wXF+*Vf6=-_fH% zUvdl5lf&QerN;l*GvWA)Y9jDYNk9HP1ONRnl41NKZ5_@(Q;Xm~JDD&?lKeB<3Hd(; z6Kcm_1WOi%e@ch($J@`K+aLJDkB>L++khh^yFVXArx7(U_9gt4vAl$8Ap9r9-+**Y zBK*0?ELrjYGI{**{Aux)@_?W6{|B55xBB=ml)0SApgyDZ;~?c!^>~a$4c4yk7ib4% zki3hRP#=VzDq}Cn6_{7J)zte#^vq}v(sMlRgq@yC(@&4+M-J(UnA9}G-vak>Cp8KA z75EKI;zYoopEmd&6TYqW`lJoMGb;Qwm`$WdK9x-3Kt4DxMAcP^Hdxj0ir9#f>wkHK z5B+zq=Q@-?S&7q8+!YAR=AzK4^-5oxr*3F)t7cJAlzp1-!5Itf(?k`^Ce3s0n>3$7 zRcz9H4*y?DR3&pH62Uoh{}E2hF46fKbuqp-ZUrxz9tHInJL>5c)RkeVPY$8>5%ujs z)YzbEMSX`xot+y(Ju?dGkKeU%J=21EI6mFitER{G4&3>Ki2jSHYH;nd+OY@mykj;b zIZr9MTB08{nEW7OX}$kgy5%6|mSFjYGF`EY_jaC+Qtqxf#_rvVgTnFD0z?$~RKo)b zX@#y8Qj8S>n@jOw-O-{TKwG!GxZT~SJ@?7}TM2C7f?63vTrud{K2Y*};er_0iXEN|9 zrfB+-L9kWlgX|s1J6I+9GLlG9B^p=%UIuX*-jXnQlj6dQGv0GmqH&Y?zu{1XZ5QdL z!NwWS6Uo;Ce`zHA=a8F;-`6_;|Ex&(m!=c`hnUuf$>)m=X{3KnB>aWxgx@O?{wXQL z*XNV|4pEmv)keLyAKBdvP)#FInhspD%^x+$4;(Oo`qx}X&;`L{8uQ%vcQ4+( z7?U%C1HCWMi%K+EOb-7t26aRDIlZA3vfzI~YUt^Xf&bK`@h7+5UXIQ=MDVnA|6|_m z$UW4%nzb%qYpTk1-f<94U-HUI>ehp}U)AZA1@^|`>cYl)R~_ruyQ=udqdMaxJ6S#6 zh;tEfJcX+bM?U--0)k6SH+4&s@7c|-Yz;;#69D!y;M0Be3byXxfT zCs5Fw>%xTURS8zg=pS4ua{!jlAmOp|*GL2a_}AU5$yQK-8}TAoh=8D9=tNV3bHf6TBDw zX$L~R0->S$5R{|umyq_m3`web7gJ2=jcqtYHKPbkprA@^#v!Q{Pcm`P06AkpkJ#lrGUG*Z+Dmg=F?W_PXI&mh+9o zNEw~33YIONkxC9SXncZ#lbZFlnwjM-!u7-DM7LI<9y;s<=wh^(_7AwCDAa546FG1FLOvf7k z1b=$0{1Pc1L9YMFv?>msI)Dz(*hd41baapXO~N{GJC1ek-|X?5#<3jJOg0Q?EoJ zkHnwm4mp2!a=zYb318PgomkEU^gpOg&_AEy9A^DbRvy8)q07%vKpXY@wl2mjTh=c) zCj>$m+vH*+8MRc|30)`+d*s+y3U7tizN6Cq2K2fY=@UgkzsOg$zld9RzaC99O`{IE9ftg>&=i*4Xy8&rEObiKqOIU8)gFY&F)zDCcnhI6bz z4mI1V<{|5vp`+eSwE5oTd@J;PD>&Z@nQvC!8YnXxRBO3y^Y}iAL-JPGe3WyU{l#MY zl4bS{#rC4moU`mJQq<9Xtjos7B^2k~)7fVLjEgV&*bQjKdG1R4Qs`BLTChqT&`foF zT;fb`-miT2B@R(rqW7Uyyp8Fp;Y!fHA)S7{Ml?BqIKK{V+OsCb z>HOc5;zWIj8Fet!RT_}ctQ9{p?*YJLk#0h|7HQH=KSz2A(iWumAU$KQa?@>dW-8NX z%)jYi=~dBZ?$~lben5Z8Ixzj^8gl&DQ{*W{@{}hTJb_c%#OP=6u^DcA2Oo!kaRr0- z33$e`c4&6uJnW}KAi&U^`UTPoJ{m_*YTgOw9Z6xW;4f@O-?qjT#O*)`t0Hp+tyLs(thlGgfR~ z@Ywn`mRvl4kXV)SabsC3m{!+Vy*aH?E-l1D5q6Jce8aTu5WmL!jV8MN$H_iV00G6R zP?GQx{aNq5IDCx!G7b6xSc80CpznD3hn7L95k*uFBYyL z*4V+Ii=m;1#hdZF0(B@KQeBfp%FSQM5oaR&LaO}>o8AP+;omh$DG zF-T_D803{FH3kVVz*}XpF+k2!(HLOMA3_=6w0puaz)IvZGr&DmGWz0M@3e#XH@5jD z4F+FR|6{7;{x{Aq+vLlL{SWzjsOFb*V_}3%YEGJ(mmZj3wCM)34NjyE&M+%si!;wK z>tU>mMNFIl`)K4D=0Vc8Of$?6SoLE8koF_@!DxRZdn2E(EXef&2bReg@CXEG)Y_T8QQ;R8e9%`xKO5~07e}pv z;Wq{NcURdlNbCAhaJf(Saj@m&6x5XIpNVTX*jtkyPtF4J<>gOz`cV|C1vS?>R&>X_ z0zV8#l0j3p%!ET|rq_Z~l;X*n#n*HqI~~46Y4TF2oRaI>m4C&$HtYXP>)LDYr*$pi z3f7$p_%!wtwKK`rPyqmn$L9@5FW66+!1Rb@A7d({A@*CgA1X5il;FP^TKlmDjM`6f zuQgq_+yN_YD_QYmTPej|MU|mJ_oIMpQ1n4($ietF1B8@69nU{ze4XT&qJ@wbR(PJM zp!=N)B?f62k*e(VfPnQ6okR{7G0q~FF5>SX_oeEu=_k8*%@|zv1fPw|9{Dz~>_Jp~ z(QbX&b2A*rS}ASWvn#Od0fGWEtJI|EOy3b$^Uy4`in46$-9ks4b?0xey-FkDN&ek{;Z&8hVX z-o(hOvEf%uejfz{zd(X7JENmNX8Fn8H~?Jm~CJoq<*bbEk0b^N?FQ zanHwwKKRgmd^ntd!KX!J%%s{X+=W)fMWaie#AGiem-r`W3cTuwbgI<)WdlEcsy}Wl zB@^PTYDFF2YlAm$O_hBGo~ex2zLY`2`fHU$uCkM`!&w(T`%-k&8tkNOqdzQd+Qf3W z4e=Vc)zHt#495I+ykz7m6q_fBvEj1fRA_(h!lg=q&6!m~T9bH-qew8vR46VO>?#1O zCf7M#eyotD4w#1}A+=gt#PM7KXuULqEInrEHGkuJ8bJ5C9%Im1M)Jze*!d`9UV))i zGuF9@YQ&`#3y5MVX0kTg$r@ghz|`#s$O}LoKjLdokpxujE8NXkRKjk(LLKed;LTan zuoVViBhdrtV80BHETm`8 zn4`FEzh%y035GZb^0liVc>Md(aLmWXczFhrzFdE%#BpyY#VnUb9-;Su3I z5Dwnu`wwpf!OP3bOEu#64YV-y^#0(t7p4SiZ(k$4$D_mBBk70xr8>D^X*Jm>pzm6s z*E__6;qdXLxw)bWiw|1FN+q1?0QJ)%V$-qrxj&-f*GgU& z;Ag#?@Z0V+;y0!<{LTo6-$FQZI;Z}A;KzaelQjI!$1I7kDw3p71SS2Rozn^Z?p+*) zezlJr3j9jRx&Zq96)jcCpWhh2hh&!#PNJ8Vq&&b)!fnKWoh4(2=UB!1*_mr+ip>4EFZ~ED;>y?X7|SJ`VN7+TRt? z`g_eoK;ww?ca5>XgVwvS=QV{H-zSo53;q2))=S~X_u%m3`zZ`G!}#W0osaLu$j$vt zqlW66um$y!6R$~ZST0exEcoi5pf`tw3J508-?*Ny$?c@v&P%9cYWXk|l& zJ_%P0{Rg0G9&T1(@gc{*QeudQ>^eX6AnOBK{;9Kz{P6IDUEzn>$Zg_>X~E8CJ^%_= z2VW^1h{OD_fmD3vhjTmShtDuK==^X41ers;2Q7;fCV)K&Dpp9JlAI6A4?9BmVatB- zLlK14k>ZD2<`s9dDOMhNCO2Z{`wZB!v0yP3>Y9K?W*2V!x!1zq!5kl^f7BkL8S4F36| zY^d&<&(OaIJhOw=a4$!V>Ue=mMvCeB?Sim~F3Yp6%8+7W}; zWReU}zMKlt0}_qH2{&SINP>N%L;M9A0khxQD*H<0f+c0Gv@@;MZFFRUjt4!2DEMr&rOUSgTRP|0ZRx)O$7!WBTY7Q8mR_vpY(xkVq5IbVL7Jl~#4zcL zQ7C_mxSF$8yiaPFT?E-msCuxF2m}kQb%@E!sEuH&mF~ioY&#D&QQE}chDxE@S9;NQ z`&w|d5a&;$H=+5~Azzhe3x+e13iL%kA>^z={PrGX=MT~hwSF(mP(wUqhBB`i)STwb zcSLppS){ThXO5xDnKSXMY(z=gdy|fIDblx0-%p3o!DZJD&{$qZns0bPxq+NRSP$={ zb+MdZ#O#~RGs_sLY|&?y*y=;2 z-PDOWEqeSq!(SbQUp?6j|B3^I&!TWJ;In_z_Od+<#7fV#y_}ak7EdV@v2D$@ZRYKH zXrVJ#oCGV9k&qR5CQghcE`#YANxxzL`G&_xV9@2n;5|jN>!A;GMafj^P*a?{T~^;2 zh0Q|{^<(|-GtM8*!2B^96_%Yv5`+qU^|XE@TZbbTnP>?>GSd%V1;Qy201xj8v=Ohp z7H)7~&PK5gXa%N{wbTx6s*sN4L?1*ZJCbK=j%2}(+aT4rW zc7M2jC}gh`7) zfA%|cS&k+18?R?2GI&?5reEK3`h95yepP-mbQPuNop^h1mGcetP>u!IfLXi@l{6+b zOa{paDN^Z*y&eJsheys@uaA-vig(poqyu7qqv*E@wR`BL6#Hwwh1ef?cV}Wh_cjvy zE-CgWf<990u^(bRit2Lzk4SF>J~VB=jr3Zi$-GsK^lh^g*GFGe-%PsKML#g-GTHWqHj@CBzexF zvKAU?$a)nK@i?;FL9{ZiSNAe)LW4A>K_xV=R~>j0UHj=c@S@H?jPHPs_>w1Ewqr!I;p_ z>Javn(gM7z^S}m56P?AA~BV&-7;F zPzXw{3lTIaL)YCgk&O`Ht`7e@ukYUql>et*UBQ-2%@_8AhlwH%SDv&;qd7tUmh4%gP zx54&R!abt3FC7F9wvW*@v~NWM5FQEI8`?MdCPVwCLBph8mhD?j*|qkqNBV%<7fF9% zdqNtw%6J|Jj*m>#Pp;&(ur`&ILRX8zk63>e8ud}?GoH=1_D7@2E(pg!;p~@g2$}q3 zUrvp92*!K*`vKG`ZOKW-xW+4KYC)VI;^R(3e4N))ZCr=dh@U}PtNgN|IG!d!;r2Tr z&>-Mm8x>lX%y)s6K#lkk(ovf38b+h6kFSqK!O_>UWYp_Dm)8_98k7@Z2nX8FY=H9= z!=aZAiGbs7vZ@u{$JXN+W28nbK{0x_!}}O5C~;(bjd%~!y7*fz)su#L=?2T3Qt>3l zfY-i}l6Nhj- z%nQdtO@}iM2SP0Y1w{h1PQxKl{O;)+X;s_FAyF^h&WA(=PL%3DO9H5aXwgrZI`tX@ zfI6wV)ak0rdbxo}DY6W+e)rXVd3=OFm_G`{z2u*6UfB3%pwB5KqZh z$WfWKm`GJQ!liHt8Uc@9N1B)9;@LgH#W!P_ZkXDNCL5-~!Uz^)j zAg!<8mm_^!f$N~2eYHP~$ov(wpzH{5p$h6df4@Iq{^$=niIZ>Pfaf%gSfj++A>1uw zcRCyH9gviDqh+x3B0uRye;>^UgOFIf2Pxc~yoO5P_Zz?@~LB2Rr zqdo+@W&GIKuknOR&vEzwf1VKA_yavQTIl(CJj?D%w}Skou#g$LYbR#3z-2PE(85U4 zShRge{iy%|k)3f6(g&i8gzJy4(t8fPLYldW>75Vc5nvvq_n^T6dT$|ZSEKh&AWk(Z z&IN&C4bc$#bV~yU#ix?J}D;13#t_xMB4i{QMh4@iYhX|$@{r)ymT6G41u1pjV%K*?_xKVM@ z9u-*`=pmc89VI+|o9ERZsPUm+pXRT$#|WE)L?hn14ZyHlnR6R8^RXwE!Za#W(vMJGfH^S{R)E@gHB4Lv|}M$UctiJ zAdPm7Cuu|y0fx#C=CCxvI+Wyn2D0n(^G!&T?}^^ufHW~3rN<*pJVj{-(zG9D?u|Fi zn!<-z7R;Y9{fJNL;ijD*?Yl0_hb)|LAcqQXt6PvOGFDJ$C(>qStCYF-a*PWYG$3;y zM@Q*0w_TIDwwH4k-~gQ+x5Di#gC!Wk~q3+J`mr z!^>oBm05prIo3mu!hY#4A11CsCpL_QI015Cv`s*a56s)d0cM-DT>pZ>YlwZ5%{>4) zVVDL>aOrupSjS;x7MrJsgn`v~;OlsNb^8;6)=Km;bU4^M0v~@K`1oBWqy7R^KDma= zFl0*(WP49$`zIMAgJ7D`7+HtQjucEYE#AlWVAW1}d_J-g<@#3D@G@TFeAAgUv68o6 z_0g|bau2;&LofK(q5e?}yAviX-v+$H7FBNQ&|gz7GWy8(;=v0k3soRgPEsXe36h9I zcopeo_J6S{j@Sdj`W&d0q&miaSL*YAKZ)@X*NCyzqhy`&*~h` z4N{(cIh?SuqA%zWJLfKm<4+}ya(-QSA_U5{SUVd8kSm7-5TT4Ny94k^0L@$hwNhC^ z*|oWI4br;&S&j6JdGij-#L4}m`6qmZEoBM7OIr(6c?JVHJS%0HByql?5g*)}K32ST z15-rheC}#QQ&0g|&y2xS_s*0}j*<6__+Y=J388C9__+xcC!-=y&nM(T+P<=$Xrm!E z_?C|FU!TG4hzY(QD8b@w+%L;$KL=66w4n^Zd6tCPsdEQ31HQ1Q`;GQ=4LXRExn1ij zEe<%iwMUX^1nMKPZ($=bv;fOcyVZ3P+c*C}hG*U`gIMhguwcSSYs7qE-pQsBcN=s@ z;@cQI(U6Vltzm4W#}w+u5}34gcF{;ODN0S9!DIU70v^^^IP39Cm<5cKj_V9;RDN(0 zqOF*&Aht!)X@sze@1B4kCjx0=gTI>K<7x}A1<&Kg0d#r93ZlZ#C;SHkJ`tu>oCcEy z*R+29RMHrXHPt}_h|m=7)oArm9lwAH#t3(51h~=Ql`;Jnf>{Z&7;1)mRs_hB2^oHD z_Pm>jQoXsR7E#}yYHSfVpA8+D?(uDcU%_Yp2)cEZCs~t=K2DK3n=2Mzg2xbYz%?;e zY=T)Lpq4K03o$eFJ$G>x|gPMUDS zFE)79@amKnW2>kU+rmyjnn)BIeDWHZ@y+N2cvN_-AEp7GP|q<>IPXjfPlAs4`oZ%d z>m3GLj%7vZawwWi2Fitzu^=K?;0t*_Yn>sUJq;yjFi)gnv{&d1pd$2%KVoIW!1j0$a z^k!#hU!TL6@p?9(lzS`v(%zZ7WHKJf`7+sFknh|?O;prgJC4C9xbJEpr8WON*?gZ* zp%&f*brt6+fKJ#j=@iC7*BA<&uNP`Y%f-*Q(C(jcA$Q>p#WhmJHX_d+d~|Q6U&ZxP zTp$pq`se{JC;4||BJVyQ1C6mGRrPsT(xe6gK#xRF213IA4ff>llW`N2tfGqk;3e?j zmwA%4r5(nClC|g_;*|bK6S;}-8Awl`eY0}qoLgL%x#rE@4{>c8D@WoX>iC!P?>5i_ z@^;BakicD^Y!q9S<0FZI*x;9vUnvMb!w7%oL4ZHW3_soozuQ58-+HSFf0Kdhap-^H zW(wKcvC(I>8NTV-)yoe8{K01Urb+xWtW_i84|)8iQ66_y|9%zz8r7Z-^*SwAypu!X zz=CBoS!oNC8j2vp^08;HPQ;x@dU~ChmKD&`A=}_K!1}vRC|EH{M{|lU1Mv0*-xqYVBiro^_ zIF;goYQ#ExcI0z0KMX#+jiNnuO9D?+mqF1)kju$>Jtvs!dG=DM(ZdMJ^#lbs!GPAu zSk_q4Y$$Vog-}GGfnNIkQ6?eTpt@w)2KePG4M}gWCtH8{TO~JMarAu-*%AT zbN@^t_~@T2;9oIzN6)C0#MU3JfJ^Xq!ro|v{}hBs=dzPX2l$Ym%6fx7+lFDn`fOoo znGNX>Wj1KU_vSQ}aq|{Y^>k%$J$6{ZIms?uBp^ns`3;=9aO2jC2L@5bU9|4Q(67e& z35QejA;L{U9Zuhn4Tqu(>{I?-JaXV9Yq%quM9~TORxPrjg5srahOX8VTeL)obHD;w z3uWrD(I~ZF&VewzCFwQj!02@)`GR7h*Nx|LgTvB`cEK9ym0+OP|nxA?Fj#@1BNdhWob|e zU;zx=pZa|t)>4c^{q-v)sXCSHl9{8?OV+o6d^(2vH`R{yUEPKHXm1WAim%Xgyf)&eZwoC#0?oQ|sGKqewkTC=1p;pXBz9L37D6 zGr_4f5G!Nw<-mst_lIB7$LN3jC7FHtk^2aSUm74VHT|?#aDJsCKw>-Auo01n2)`WK zBW4 z=z~^F1=zXyBAKDH6LZz%vF)jKZ2rrDDP%XaJ}`p2uvID4E@wrDu=BXp%XhV^{LA=K z^`Ol&C=-!3VZ^&OAO3BFVLqgTFQk1Z3ssh#6KqkZ=aa0Z-n(fk>WAUv8qAJ}(Omio z3g(aZ_J)ppuKA3Bv$!3>a39hYz4wd+kf` z&Kh`EN$)%^pyu;U#;=$HVd3*o5@Z#^mV`(7WgA>H1MN$o)ju?F+q)o~BUq}vKfW=T z;O9~J3_R6hnn`ojRrEYo`UZC-A2vDL`^z-8_F$5b>opfao8k1SkKZx;&iug?U&8P$3?Et*2|Dz0tJuKWQxmQ)I2NHqS$K_PGLjdP zqQS>=ySHY5h>9zfELxNluboM(V?~mV0i?g6FfNI2oJ8d}XQyCKPj9`30Y5|U4%eTW zt<*w5rrTuPTj^JWOi3}l6Ua;pY97XCFK|A(yYsb3r$mbIf$67N0N_tG?*|Uhj}CEy zV3qXij5<9rO63`xM4hw%b+`>w1=?`s$S$@4_(9)ZVU#b#{ZhVMfI7+s0dho@n>nDH z-hz7V1O+X85_cES5z|HGBm_kf&>LdkWpiJGF$GN!tfGHvLl0r6Wv+E-UcJq8Vu$Z_ z{Jm;~6>vg|mh&f8%(vKxkVd%c`6EJdQ#?Cup4ZVf?Y2)suo|+3)&ztFyPbar6T}dE zwar&;tc5@MNeykra)2t*+H(bf4;^Iltm=?^*_GhVa5W5(H5A??Yj^m36fB8@tm0UO z@_H8IQC&s9-c<|ns|jP(M-QSEB9rDvd$pt;qn0r&DEAngxCZ8i#v;Vt5u2C^@|yuf zXs@pp;M`m3R~sml6hnVXOh&a6lhI$Iw-(m91CIpE=cE0&xxQ7U_(QkSYUHqBs?ZwX zqoU%nczUsrit#T+c4l8d@_z*Z2$pz`+TdF35bvJGDlX19BQaQIU!H+KPOkdvg|t;g~07pci{#) z9ka!$K-r{P{J?*g%=0AjG`^03rAhBbo7|a1a)@7oR+=bEM%E$x&gT1!YUMOWy`JG* z=)Ydxos$oV;Nuy=A^J*;<(3|rexWDP4j$XfBaN`O6GkiW03%O#WLaj@o{Y~`3 zq4M6SqVmKgpb4W7L4*%biKz`WvJIcYGbF)#afP}@3t1F8v!C>2nQ==XqkAE)7U~O< zSU{3MLx^_OGV24#+OU@fDd6ouUG?()A_AdxRdz-$sEG@9;1zS^<8T!!Un}$FBA@Qq zspCcbCr4&@cc@j)|Cz@5pRSDN`M+>Y+3{$4$j~?2+gJkhAeWK7$z4iX z2=*QR4!?L-i|N^$Q;&4z64J8hZPgOaMGrJ_)FUCj#>9c4b6)Vx%mjd}7JXrGlG`a# zgWs-_-)4|4Hvr0ytbpi17`kLv3XAgdtlw76wR?+iVAHTrRqnx7GwKS&dkfiCC{u0)z zk5XQr1&pb!Z`4)vAm`qCWD$>_Ow=$(Ba=%U{C)w&FC8p{V+RiE+6$gv=-vaVVP<0{ zFMAgFhcKCOet9|<=-bH!hFL~8u?i9?i;oXV!`<+C0fV*5iG#6Axh+hx_hyqgV(Px))*Jc&Cpt78AGwvR|`K2 zw4td`bHGI1sKWQ*wkCz5Rs0F5MtD1=*NonL_4Qs8GB-(NVp*xihEF!|Ax#B0L~1Hk zE2~sDR7#Z!Yz614Dp_l!&eg%?P<;>t83ioWMxWL8qj@`(T4Ja`&+k<4A#l8V<45*Gg+;gBg|T{4>O( zvCiK^LnA6hzDXczeXo*fvzY2b9lcNo{k`YsRKIDn#<^N`QFi~uR$rP{-&qtzi24%F z=}_P6P-!F+MCd*CcSiI_m2vwvklzON`~v^(Dy3$@RE#{tVw{};>jQ_g8hK}$R&&SB zj9TAIRNo}3kH9ZtnSow5x?w!kp$fZi3$Hu z`ic5Ot2h;wpb(CIga%D0`$Vme`)@V5eyIN@%lg9i-!QF$j$HDe(<@95&0h)ovB_b{ z`#U$Y{DZba_YT=M`_9Eg16{UNJnjC{?Yp>Dt(w=oG>rad?e1s1W5d8B-Aioy@GjXA0OaX+Th>JUNI8^ zzaY7L5U`HkuFi7A)*lPWtz#C}=W3{Tq3=7x;m71fDhARoef)};r0p)|V0N2l^+1nJf!UO?ozz7~h^AY|pO4Y*gx)((CN5}o_c4@D5` z5u<;d>n$hmP2dROz$U9)@!2UU!ZT$Q#JTsUg_fNY2w{g?a_8g_a|273W)7Mz{EMc>r zMZ1x~54i$Gcmg@T4x0dph+kYd{5E3|arp52-{zj9t&c_l=HE#6BwmOPCI=I(cz=Ma z59qq&IU*8K|x=&vko7hs!D1LOT;49=UDw-(-2C z6?+DP7v75qbh2Uo-%62O*bx@a?@>dZ^6;K9eJ%YdC$Y74}4162_JsI!(_A_Cd7!szB70{ zzm<~@2dC+n&wq#rvNL!OlC9>K5}wh-F(4u|%^yXL39(NxynY?w)xw|R`{pPF?!v-Xt6?>@3?K`pc`!kDKN%#w%4_foP+Fd`o{1NH7n|wVXl*&iIxJ%QN-{doZ_?qczhB4tYm*K^`=iD;tnN#MXocm` zOQ+w`U%I3l39C0d^gP@PC5kdkmFXK5{@|{_|8pXfAU615f3}O(?d0e@V6Ns`ypB+u zi!_+Qz#)xsqT#Q@UmO{Jzs}%Cp88^?N>SqdI@0i)lwkt621p zU|=S3BFu)rrs!C0k34=d$5BN^{Lu<-Y{*)AKcOTG=*xPJi0(tZEg^f^$v8|ljy_SQ;;hHhn6oct3{e}V!P!t+0wo#cHY5!P4KSehr~l+h^{ z(J4HwGrc2{^~AAEvy?czc9*A#3p=W#W4?`r(~SKQ?tUY=-*Rvtmah~dkBE46ByDJG zg{euzzfXZLrX!61La4+n0b;AalpIf3&UUE(J50bK^-qXcf3*5&RzCr)HBQ=z5h0pK zL@e-?X7l#-_1MlHJH^cPMSF^dPZ{r*n?zn8dEX1}tZZfTA$Fhs6?j#PrZ3Fse%*5D z(2drdsNbWtR~s*Pwwv43??|;N8osiBN)g&a{bD++@Yb(l=m&-$)ClUrX$0EgBCHCG zK~4EqAI^eKs0VmEoi1N5zM)wQ%XLa8A?nD7lVo735xce_jd$zF3uo7E3D3F@!AL8` zUgLQH&(=}|65#QTzUAhNBcxjWKsb)bY=wvXmS*nx*tk@~`k*2wZ%L4?v=MM}*o-bN3&k$f(DL zuf>4x3W|s`ugzY72-#11MaJ&Xe~sGy=V^Ul;XaaS}AJ60jeH9(+P>g$Q6sa9X_`~eKP zp)?%ip+?A2n|e?(M8jWhiX*R)_y)E~quS}imSNB#@=h>@?}vm6iBIKYoQeRpbikA5 z`_nFp1#F=0QSs;Xa2neL;BIPFv#bM0m^RE-LVb+dj6i({I}scHlgRx8nM(Lu2AZxn z>V8DgKiK5xGCZbVo8&Ldrxm6fN9ep}o}bbXEf4z1^O_M3!8eUG@dYEhU@LO_aT+R} zDl7)=prKk%LGC}t$+;Z4P|uMISZ-h~iLLNBt}uAPNWHcc$#?SD+pix}&b6WA& zmr?{c6rh)^KUI6>{bPhRw9U(*iIO;pe6CWL38NK=jXtg9N{NL&$!~K5!_wzbcAf?4 zLl=tZ^!d}@m_E0#l30GNJw(pEs|q zu02fk576rG2D6r_{U04@`y&!3hL5q)&#Bq-pfd50oT= zn|~oy4EmHsq5YNpQBvPuISA<~qi?%u)=}eT44iy43sE5Ic;oqaHF=Qa`ZYI^cPpt` zCJkl;6t}Q~IX3u%qru<(!T!Q${i_!4m(q%>rkVU3zRqACPR@u*AC@+06!lf4)mOXNjN}Hz{mVi zKix2Yti}=M91pX#4u`Ur{VIkjgso?n5fXGNRd%vBr%tAh_2$%IOMX%ffOzc{YEFfi zhPA!dUP{R=urGS;8|j{-QnrGWA~Dpy(YEwA$d9zwzE;KmEU?_GaYN$^?g%`MNE|vc zu^^wHD@VYuk4+Z1W=~u|h7T&@UWBuMl2txqXE-rfJL83pN_&TKrX`M&c zXnUN1;t<_dQy;*4LO@j?{d#?q@vBd+{2;FXh9ib_C=Ni8RWQ(e_yD~2mHKf8J_0SC z$BJIwNH7f8Im9%y0V_-&-;YKfM?SRg{6Fl)^(~$Ol*RetAEqikA7#%KS3Id@=hC>0 zAZH~}N^3^Xom}j!4#kqq#c-2~vDka>G8>?F<6AokRCK}#h_b-d+B2Lq+w-k6xS7Hs zp4`Hi;3##JtIKs>a69hAxZAfX4PVEKQ4iDClzfEf>zDV*TMC+}F)|ZKN(E|rmuPeU2G0EVLQ%E)D}k}|R$Ob=z`%0B~5$eKjO)>pwRLC3w(sa+< zu}J?7X+n;gQH!+embvql=`-fvq_}1*Jc2j8#3nCRlS2veVjrXf>=Oq0dpkHeME+j5 zOVT7coEjEeeFL=mCPA+?*SGkg4)whWy^;E$^ZFv$$9R4zh0iF{U+kg7i~~pY<^>N# zrM6%Fw5DTg*0C{KwPw2~w=Zga*)i0&8RCc63|f7E$M6b>;r*Byjutseff)2%x&9}o z4D?;Ik~_JEIq-l?P%)1Gu=Usdsq6K}R$pm@)?SnSc=jQyFFR~~ZP3Or!ViePM|u3e zivrBQekc$j{%0Phad0g;OD~Ie!%|*R*KwysIyx8;XyF9pZt9P z4edYD+#F4QvR6@oev~UxpCi@G6svp|^f%I34yOn4NK@=+{fCkQUEoL0vmN;HVcK|e zMES7`_`mr~2mC)kK-b~LzYF-LcEtCr!;bHvnkKF7BYknq*)6xi1-;%#Z#ZxxT-uPt+E$0Jzrt=EnKi4HLb{da-q{*G!79!xs{ z_4rkXcp7p~3b7_~$Pf$kgAWB9XEX@E10TrYRR;gNy5?wWeuNZ=Djzu>!$K}5yS2PN zft;4PqOphujLCTWhcY=j4sxU{<44|U_IMXIm(iAT{R9Y#*JszZ6TTsePj)!}q22F2 z=M$h)Egme?KYXcu$dexm@xiIT8zJBQ`BAj0HO_@Qjs`)+Aa#RW&6Gxx?r^f4#!toY zqH}FuX+RYTU;u!!#2|z*UHq=}zg}W+|1_bwvVV4!9fP#qKLMSy&70FAd+If4fzIWd zro!)!>3kE+rsR3Ii%R=Pin~z2dw(wg(5V1orZ*0k2)MV!d-DY6u6&8bG!)Qc#1mL; zn=S5r?XGK`D;S(`h#Ldo;BEGLQqXaL<1UZ);&&@ODz1U}WP2GUGYXDDk}tXvjbHfe zAAz++u6T13qon2~7soHNe}f0crHOGyqr^w3 zkkXToo;TwNI-P%na_1;YKMo4;_@%RMc*R&#W<^pPzH-3!f|IPu-r7898iuUg5rusP z1F$2C!h+bzEyyoyu0AnZ0z3nZmIKWZR;LYh*5JV z1q1zWc@02stk*X^ZCI~s($iO1Z4{oG>Q96XW$*kyQED>#-mmh-9J%tZ_2L6HtNm)wwL0w2gu?%<;fQ6|J(XYT#@jLW(tW4qH!#089K=3AtpB?*or_i8Tn@O zJddvw{YC**Iy67}(){K$XjMcE4KqezQLw-cM2-Q!LR=6@IUGLU9)tuU%I=qPUiB2? zQC&s9-c?KS8{h+a5Gow*xXZ^}_}8Nls9c%P(AJfiSk zMwgp2B?KDnI*sZwcF5BGOWo{lvZ^iK$9CY6fcbpuk;?V0D#afx{B%}2<^S};s*j3_Yd}%2 zhp49VuS5N#xM3ZPV7?UuAXswKiFy{NM=8)H3b1~(157Q~Hy!We=JTcm`CSmRSiRhAFMRkZ9vA;X5k_)8 z@3qk|pVK{StQ~GD>jOeW@+a8akU?`M?0RD_E=F#Q^Vu66?xq3i4)0^>m_vMdX=6p- z*(Ci^F!d!vcv&HZuo%qyGfAIe#h$MqI}jC0e>~d@erW)ZtONM_tS|sh2@hb90RZ_s z7=uT`0jPzU0~jo`Hx_%oNA3DFn3E>bU*6lkj9HJ4=Lbd+lZ5|o~c^le8sPjzWL9?g7|0!9k3eD-57K|-lNWNz2ju57lE^6xJGt>NDt z{9Dbx75wYx-!1%G%D*q-m*cC&B3PrvBv|0Y_cvj694DS$N^%^x+WMhEchB!GQn72| z!;eK7K0DvO?J7mw%R5#Qg$vu+aHs|4*$bUoG|tD*{g3d=Ue1k^k#!9edH@sS5z8cO zH{<8zt@!x@4kCv*4*D^D`~@t%e2K0rNwmOeDE^Gk;$N5_H0Zwp^h|%(V~xSz;u)+D z^s@APCe?pxG1dRam0W)iE`5JuJH8)>F%f(nU>khT|F=^#->5hpN!KXTOOQ=*xGQ#G z{IJR4JbP>Ao3J`GPhUr$yfXv{`V!WeCW2O=-b(xDSUmHLFFpd1itV4dhu5r`roKmkZX>vKtjO_I_G((70U#z`C-ryHJ>NYCPT7SA!H(BScyJ{BADvhB`ywzFlw54)G?~-L|>Lv$Fu!fgRYx z=BMYJ&!I3Si6P)SHE)MEZ%d$pEsfpvbWZbhF9n7u*FY@(*vxOlznAmSns^tJH-v|o z|4a6^>#yW)Vm-Y^~(b>LZ^T9q!mLg6?jxdd-@enW0UKFk_ z8Z`KxD;@>;3G^%X07gz5?xYDAEeW6D1vC_uH^af8@3a-rfNw5qyHC#G>;UU7Y*SoG zs=ckTKRef+2H$|Mz&6KX@!ww1T|5cUjY*<*0sd?Y)*Tqsh6L(k@YnFjO4O?j7+8(FN{*ht(4at+N9uG7@KHn?ntj~2aXqe(&H`ToW{ZV6#wd$~{1cRAN8ii_S4NA-A_ zkUb2ZDKyfHQ=sjwMS~r7Ekin*ii4=RiOsf`pvXC)MB^teci7Xfp1KfqyxPnu$bYx~s#?9ko`ew%j z5l@%mNT*};W2HIUOD=|wHprWk&Wy~U(obEQe*oi~CE*0DV3 zwS?!UMDYWBf@V4q{=|&kE0bzzY7`s2XsnefMA``vH(iVjP^>qgt-Fpfh(xvk7EGUX z+vcSA0iAS>O>qsI!ES6e?1kSrC^tzW1+$Jg8&xCA`Haxnvb87Xb6pyH-0c)Zf<)8H z{KhGmIxs1-?4vQ?=FP*cd2QSW&E8%_HX1{z^^~x;uG>R@At!V8a9((Ck+(_B+2id+ z@aby!)F#f`w5}O{D;fK^E)A>z1WA#+qr(jBBF*p4_UfGLl%9p>3cpo zOHQ-LY3dGXC(G=gH#`L*V{RU3uk+e>s5v{pZgpeD*6*kYglDb0uvRHZuC#xqt2E2( zpEWL2?X_xl|DxR}yu^jCp9a5v+IVfHeNUV=OE0tUX}n5HH;xFX1l2`_)k%utFX&Na z-vx=J(6qh_e}T&`QV%Nap9DdEa`-2G8c!9!;&Bt-cpODZfVJWqdt`2B!FF#?^YEbg z70gRR1Nq?6&#`*8yGYQ1r!lfc=|bjD4!01?ChW_H+G~5@K^X zwYL`}bN&9QTz}(Ia^0Tzx$sx=upno}I3giJNw)|5o4r>M1D0mnV8}uzJsjHrR3JkZg}Pr)`2- zV3~-LS7){lx%jRt$7Oz~e(AeXQO97@f18?eV$tIGHtL0fW7Sb7CMImd$S)d}OmAGt z?XDBy21eAW9WFey^a}SI)}fayeghz{%WPLGf!j^K_5GQ`S&3JG@U2CcFtC$~?n>dr zu|;>KaiT}jUFnpdSut_q1c$iu9)f9AFSiyg9>gdFK26m=El9lD^G(6VDK~&j2e>zi z`eU5>0TCqgn<1HZjhKiA{6f-Th>-?EI?!NHVpWAGk`=Hy>+`}urnFbZc)}FdC;U;BB5lHuQDC@2MeY4L;qWXK2-N8wo>($X>9)B0w7qv(7W&_qX}in+ZvDKIhJ!hO zKR@X!+u8m%DE)u)ZRPddZLf&F{CM}gPw}bOlINx>U!UYRqZoiq2_61VN=bUZx$oE2 z)Akm67y94acbC87lSRjGi_@#jlvQ@8Dl>O-Ew9f%U9Co)Y2^)RsC`MpYl|$IJ8h3` zd$0ZtwI)+ycK5t@45&O50hiA4xg!*xhu*E1=yW4=9%5`>n}1>mHksQ7Zj;y)Bzkr( zwCH%ef~GD3dL~MQf6(az`rl3TS9iE8THSkEzqIv9?62Z~~PKMc*k( z{fPNVUs9*gL-UCFXFLgWpW@=Gm!dap8*5Uzm-zdo^Se`KprWIe>CcV@tpKt*eyMMM zcb9+K-XDOYq3a@GdzFT*L}2F|>RYx~zDOx=NGbZ5FfMAyL}X*(iQm2t$!dG%4Q|27 z)Pn15&(ys4#T)K@*7+w$;%ZIlA)5l;Ff=Awe+L?(B|5an)b*XW=cMggdxjAf4|TaY z!IsotHop(%{MSSo=CW^V-8+?UKX~JlZnt9rEW42gRTntO+(Ny5ecs$RryK+9)NOIo z_Ws*)hyM-RME{qzv&zdG`hIDfl=x0DYJr^WYn!+ouiq;Ff?iwyOs~JRUDIm?|D9AG zjafRW?=z~80UN6gfR)vw!l>|R{=wt}>0YI*1x}&jTmPQZCc4A@52c2Vt?!+Wv!&Z$ z$hej#4w|t$nF&#z6d`du44qInLbNruhw%4(H-!H_al$xEh@<+a9OExcxdNj#`PG+m*jK3faVmyt?XYTxVFAMNw{Cy89a4mls-#-OklizK8 z_x*Rjc(?YL4+~oGy%|D2U9HBKv~NF4cz0g!p~!c;WnTB8$h#nJOy*9t^6G-_-+lo8 z`arqvhAB~I0W%L7pO);)nxDF4U&j1yL9x4Jci;Cuej}5lv@t8Ep?m=;tznFMpkY?6 zVb$tnG)j`j`fkI!A9BOCqhVih!_v56DS?J1YYnq%4Z9)QoMuF79MM)ohx)?G=+HE| zSKXGmv(bUdCZm_e_qXD!B?O&nnoJ+SPqId2D{$!zB3l+%27=Tlf$aEe!C$LR?5>d- z{Fkq^r;dV(LVVVqnuV0JN220yPt8UWZ${%!2fozXi1I~E{SlU(e?ohz134i@x|fl; z_?6?TF&f%u+9#FTdGzCL>nXHmreX$q`6`x(E5z`~% z$kU@fDm`F2Qx?D?lni53m7U^zVI;ElUeE*a^zMc@Z;lm_818Lx-c;hn0M}uy`~b0{ zzUY*uT|{P*y=`cYb$%+FcJY*~CKh=USEV6y;|G$&TM$2az$7;H3Fs{b19h0m-sJUw z!OM3pOo&eZcL>bbAbkhA)64(?>_XfhXRb!O8WOtJbKm>yucJrM>7#dRF4xTn(hlT0)?KZW>;iWGB({YIsaA zHmZmv6tVANmP8n1xm!hLajLI3>e;$&E~p`B=% z$iN~qiD9Ut@zlm$YAWMV!f04mXxKf#c%&hZi3TA}G(86CIVhBLoDbjOe{v6}UWK=? zg#N-V>fD0Aa3PSYW-v=Po~Wi$PmFC(O#wK)SCWzLq_>0hUl6f=;x5H?Rtf!OyR0Rb z`9LB9{)7L;h{)wI0=E}{4V_Izh#6I!kE6q!PH-{YVRv3j0!5v@TLF&Qc%DJ9UR3Xg+=k`nxs zhEJr`oCF;)sANIAky_2wi^epLV+As(XPFg9Qf$&lu}RSs8&a}Jv9YpZlLCb%4T_Bw zf0M6Xq$`qBx}teWwqkxs$@IfGiEi@cv_N9C#iRSl2SsXqCT+5SBZG`InPfLddU_!3 z%V|P^sd$Fe&CF}k%QQ=Q?8D2q}6s5;ajl~A6) zi@OlO5oSSz?mEK8eV}mv={^MA5*}Ix z`AbV-Db$gq=Z)s)qNcOM=|A}iB3njfICsR;gzfX}f|BA8*UuzMT4gl7*GHl9-c^g~ z_mPG4`;v=(x6Z}y%;l@r@E?w{pSk>z+5F^j@}I}1^Pgv?;?J7h;^&IU`6 z5bRcIZ-?s@zsj`|{R$^O|LYFp~8Zi!Y}cqmx!F=nzr>3XX*r@f>lJyXr*P?GO=1urelL=~eBK%9@F%H;i^(Ko;hw&z?POLLQJoOattx9U6 z$shkZHfP6#*GliYQBf<0FD$xInSb&`^%76JtEc)W%~SqYcV%MHzv-ZsC(S})7pzv$J;F4Fn+$kt z|I!B$JqLOx3=7Np9pdrOKsk+o`uFu9AFzX*j@x0ZTmQZ^@V$H42&CUR)0j)|4W3U; zA2j?N;<5mM)7`@r_!tydy40!YAw)gvTucBS;#)9iv$Ai*nye-9O7xDsWgtzp&44$M z7G=%1V`^^IMSDcgCAZITzBJ7P5YC_jW^!n0%Q5ALql@0+(DGXXiX2-`9=CwT$sJUU@Jn=^G- z^q2bINuh;e+*Qo~!>jJSN?{*vOkk)y1W$gPGyMf#VTu>7pw$t~zr)VOi%^zFe&7$i zQoMINEmRQ*;lriZVgN>8xS1!IzhxBi*A#2{Th~U&pUqk#9VXQ_ZUU@W#Lf6uG93fh zT^+ZM{^s}8?QaF$GyM&pLj|a^)0Rl$TKR_=(^pUr%jtI8quy@b8xp-^EZzxL-3X?R zO0CC5i~Lx=TT#dNsxSKTiWzeXH0wlyI;vOwg}2O^apf^Joax=&{AP}8#_VHiI>tyW z%h^?&^AT!f6*8pKSJ=+BO;JZD)gvYp6Zc2(2i%5;jnkViZMO~gcZ*Y8;}9xZw40ub z_D$^;uee64d9_6!^Na81(u?x~1svTH6xXSy0(jBKR3Jeq=v86?{fKPzS8IAg!2U8G zBpBbTnV;XS50U~%;YEgI4G^9mb26jT7G~;C%{WUeTXgApyT{bn9k$5ZK z%L&=1#GqQA#&e$rYwy)e`hGHwYp^1h%nm?$_QbH+6^m`@-;l|GKr;{k9NW@2@dxO~ z)gYS2n}^8P9kiwO<8JPH$VRM|D%^$sZZ^;FkO}YxfPRTF}odps?fG;U*S8S^yg*Gy+jPMXp$~UwoW9nnr z2uh>CKtm1jR0Bm!#aaX47d4FnPX|RDkRPXBZ=I+PUkJJ8^=zRT2Rqc3K90Wkd|1%W zxv&&wlf;P*@pp^?H*Uw#IG`ATM8pB=W!4F9(cd>e!!f~Ue-Y93!Xe_3*I9#-^v1c1 z6T*S4&RV1qHiQz+JxDs7X=PKD3C{lbbq=PV75MRa{J_IWqSPUt;0+I>Boq@ORivBWZV^V1r z^+bOB#BpLDnt|34O>ZEgK04t5h>G?hp6L4I%$*!ymDxV<@80XNGDv|&=x$A(msFaJ z>R_Tz_|wpu`DZUn&$MlR!%=!3UOMLjrGZtBT(JRhPFPU@sp3;c0vKY85*lBfQrS(p zp)yYCQj9KN%WMNPwc8~X!CQJ@7WjQ<3$r)Dp$V5*1@e*+9#Nl$ApuuTxpUc$PNmou;_ynP&OkPSb;hLpMm3$x)gEzLjGfh9IT zIPyb2`yQd!h!abCHSJ{#2p;AS$Z*Z2eoVTI#kdLW7kIMKu@3Pje@kBKw|UM0k5D|b zdn;pCVDVrm_rXgP>@C;)9%LiDon$Zed74ldm{b!c+N&1W6CA$FzeoJia9*!qRdxQj z_Lr#fvVi(0=USlVXn%>y`8-^ry}+t3yc!-v1=MtBPfTDwPkn29`)f^90%vW?+yROR z7zm+}ck{hOxeSGNecj&vy26~PRg2>sG%^MXZKYi8FHw)Ek5HS{wAOt4_ zQF{+Z07%nsfW==QcK|FNeUNt{2lx;1y$*`+ZSEV~ztm*uJiZqiJMka{Q+_v4r}(&A zv)WT@z+{cbV^@O;wWDY-y|k??SIa4e76l+Y5$(Jm8)bNWnB^4@40X6mlT`(Xc7&+< z4Qyd<|HTGTwIWmm{T2ozv#9!YF+|nc(0q&W)+nkrVR~@DhLxXyDd`tfkCaxK@7y51 zCgX#?c0L!t(Ya z*i}gck^Th>>6POz<);jspAvALN6Alqqwf-LKTb_t#q(8;)obO{^>4VVL(H*KzNMJv znphe*;lx>nl?gaq(D|X&9#qrI7HE+{kr^G@eOlNj=3R zJ)~R_JyDrlac4P|9wZ7#R8W}bU#};KC}{Ki7S*(;rh{qStrH7Q$hQP@J*Vd?C~zt; z<$=XFZUH_I1>RpDEUC*c7HKd~FJ=oZ;dW6t+~zBDagA2Nb8STu2>{C<1z zyKB001By(P?pw7PV|1*u)bOSjvC~=39lLK&KLOl@=sV~OeoZyJb&RAJCJPj<;$I7jVVpsGHq;hXZff+g=ZsPDS>#oO+g4^UUinr05UAlsLi zZSzdQyP58V|DNpXSvDE$HWS<2-crlIt#P*=YrAIzzWPS=8BQ~z?cPj0mFxo7dza=A zx+S$T-Ad^?nQo(Wy-X{RrzLx2I+4;srY)3il4&cYn`Jr~>6s-hc;F#16V;^PRgmeo z(Auh*So52LzQL|d(FX?N!XIKMrj<@-YEvtvs`l;ZL&K#emOY>c=65TWL_vOsJoWjA z%B1x2K|ru5kz(R&ApxVO_aRO91GhlrG!Et&0SeMDoh!jTARMyh_i%_RD62f83or=e z7eLNOZ2mKWFT*9Bi4~>h(*oF7w6r*|Dw!azpH3js06c~5D73nO1o+)AByH)*PgBh@ z?Ztu81In{gxgwhpgK?-BA2APsZV)OijUStpRY`5KKLo%USdLwL}I6ToN$AQ@Px2T(YTSn%G znSQ8u=?QPqeuvz|pWgrcG+Dte;gDSSd@22Vqm!@?X%MYU=gPkrZBt(-cG+VA!L zobUJE?;ZPxf9m=Dew3e`d%ow-=bZC7pYu7N&*z-e!MtT--KamwcltWs+E*X*Hcy#$8>czYtN~t1;Te2osqY{ryMO$MZ=&Wq-n(`N_tEyFL z%2S+a34cf4wq0_vszXxt=N(#0^1^B0kMsBr3Y3t~!E-3>5RFdZU!$G8Y)ew0stt(f zS7Ev0G-P{a5$DN@e|XOj^lbz879T3OKW>P0sF*GlRDN;%QydlS95xm*p^r!Mhbl># z)kA(OCWo<0RyC=>iP>>p@-4}wW3%F-js8iFWTjS*Evw*Hoo6lEwD)%dUA@<_q<0Q$ zq-uymUHoq(01Fz~7E2bSq6huXzAK;BXWGmuTy^6lQjfXeaPesc_g|=tv)XL(6*t^{ zV)2N*O9xFZethZ6$!U9W^C&u(1R4_+$R(=B)3-~Oq_{B+v?cqv{<8(1blfg!VhYTJx*lO^wLC;`=!7T3yz(+rjvoNh2?aHhf82Im-@YjD27a)XNvE-^S~ zh-zGJ;S~l~8eDB~jlp#W*BjhmaFfB!2Dcd8YH*vu?FM%k+-Y!^!QBRH4b~alXK=s4 z27`wTHX3X)c-Ww4u+?Cj!FGck29FqwSX*)p<{8X4SZJ`w;BbQ@430E7%HU{&M@~|2 z9CRgHxZPlz!B&Hw!NUfd3^p1(WbmND27~(z?lV|tu-4#igF6gvH@MBa}3TlIMZOv;B!O;ds860VFgu&qkiwqVT%r}^4FxOzj;1TQp4ukCm+YGiE^b8(0*krKL z;30zt4K^6uZ*ZT%I)k+acN^SgaHqi?2DcmBW^k*)Ee1Cm++=Wr!Sx2$8C+vZ{P3L;8kM238v_pMxxaTy=6*bKx2bYpUS~CLpZ^t>QH(}y(u6b(sF+ed zb@nxAEZUM~M`mymhxOk3Uv8OU?T9~@Q}I^T^4q2!$>)Xj7>VM|Jd=LDIWTizv@P!C zwwz70xAj7Dpvu5|N5^?o$g^)3s!D~B5M1hlvIpEpI^199X;;&?U{Aj8dW^PeB_gK# zV;$~m*1j|e`8Du(I=g)2|FZXPyxqLg%n8aa_`s&tkr<+sjFErkpQ5;agH^WONhHNb zypMbkZRD(WhVBMJ&gbnWMlhd7y^k11@bP1KV}SAM6@Mh9&M!^O!oN`XkLZg3rG~#! z3V;93i7vQ*6MK)t{Y!+hasQ;V1s&^v^o74D?Msuh@Sh<3=Pd5F|CO@${{KBDBG-mr z5z21E51skwjqHEJe_9s)CBlF6ZC&uc%KBd^h5vBw{KyvCx}&Aj(`^}gR9iZo)#mY{ z3@;I7_w~=lBM*+#%{+)-J^}P16-CMR@*OmybJz-`eJJ@sZLKdKZ660SX(VR1T-tK6 zpP_PyxAh#mGJ&byau!@8mK?GYb#a+@=te*O1oPBWMqL+FIVH)AkvfplFQ#-i`|jhI zcU8x|72F%tvAiN5m{V~a@S@70^@CKs^859}Cz(}w%&M1WxmopwJQ~^`dS&x2Z#w58 zIn}09a;kV=UUH~z7RllV*Mps-$5KK8m&t7z)xtF}IM#Kbrh*{!c6^7weWp*&wzTq> z4R}X^-^%Rg4UGMd^?IJ4@b)W{!Eq>`fU$?kGf7EoPMQCztK;h>LGov{K@7= z2}2jO{Os~_&5sr3na(i&`hJ@qN~!J`Nq3B(M~8DQNfF_U0~OsQho-DPei8GI>*HoZ z*>nD9&h+zm*Nfl#>^YZ!{=i(_nkluS^kiu*SEa?P_DA#zK~wW~;`}8`edMm4#T0bB z4eKA#-*a^w3AA(fP^m;({>`tk;)I~akHo8*%yW9TO=7CrO+u>LohaRhH;&Ez^wj*E zmAOk8?XqOEa3rbYsur{w-ZFTS3$M=!Y8#S1w-i-aGHS?bZd6g)}0aWka;%P7G5=%_fsSpr0jO=x0^k1hkeSp*^Dr)I3CM{hL2CRFpt@ zl)lF>O-TDR4goX9(XUD4*nBp97r$IQx0C08{K$MFQK6t?WW1!?*Y|Sl@hiQPPBD@j z)a;QxUUd-b&@F_@m#alhC`c346(APhBN(Y1)GUHbwx?3^b1$=k79E$|sIQ5QY6257 zrN3!8=%yHR(mug*X7EGS?q=OJ$m%kPKdEYYx5tvM$j)K4j(FZdQs-J9-?N$os{Fkq zUuD0PksH|B7u}hrwwJNoG@ng;eRRu6`T`&LHT+3!RPl*f+v=k`(TGNp)#jof-JL4k zQs#XUUdEk=w7j$Ome5-CbqY&V%XNR1Iq(h!ow84z=hwU@HsAgs={xHTlxVN zC%M4Dib2im44Z>MtbF4j7?8w){a|941|k*R2ZK9U=Ivx2p+x+UKeg+t$5Q=dlBPB) zG^2bygQCkGnRA~w&(dmzR&3|6)vnk6j5#K2<|AP5(7?C%MmAktHE&P7bg`==c} zB~eMD34dUME`M%>dZ6pi1csigBgcW$e6ngz%AdWB@V;QK65c|1B=Nr?tj<4?67~~T z$7?=6K{#mJcEa;+sd#V2@((PyrQ+5*?|9#Wk1m)$ZC(Y2@!Rj5|A7UI7eou$;svpJ73F@G5GQbDOr5vv)?2Q=W8t00CJgm+4fwy54E_^u9jmn`>!~Vc zM9!j<`5$D}gcxx+&(?%rU@zh>FTO%NdiYe5|Dpl-s0_stTUW%?eAJRK6AtO1Cz66k z_T4V~=Vfk+9&~(s`2>ijbgGC(GRatI<74`6`x$%NbR{XoyGJnA>j>Yz>?6lK9<(pm z&w8WI7WNW?)|Te2DJfdT31B>T?jE}6oburc*!)=DZAb8ubug( z4`JW%Kq%H-t|Acb+?n$%gjQpiZK8o?B$F&|tp7JcGFgBL;OmuJhau zgY5>}47M7Sn@i`phYdCvY&3Yt;6a01temX|w;9ywy3TVY&~=`>)8HpztVzBMpu)xY)kdA_viGgZm8b zHz@gtRvSEIu+dvcYKvOAJmo7&AE2;B13)49+z;-(b1H(N@|L3s)FiZg7Rcl?GQE zTw`#Z!Sx0=7~EuVv%xI}w;J4LaJ#`B26r0VWpKB_T7z{4_Zi%8u)*L#gNF<@8f-Fn z*x>LSjZu-oLWB7RM;YueOF_HAT7z{4_Zi%8@UX#LOP^ zD;DbpxxB%MQ%KK~BlX8kgfphDElOOO$E9`kR~kF3zp`+fnAz=P#LPZAB5>iW7+hXU zeCM#8@PH==4gVbS1J#9mk233$A)J?#v21T3gmT;3pT~DD8h(B1%A%OJ?Ojr}<5xit#`@E;S1PEt&9Dx*9Cmn>7ljB$upBx zdBuNQdVDJP!Qzgkvp9A*Xnf~YEd{AbCscPXpR$UjrSq(NF2gV+ z_@!vXxf~@%>%EJLG*s6YY<$9X*G)IBed4IQ2i=%};HY>&_oU*Vm8XRA{swz(j7v!35}(wO&rVJJB@ zsz)>ULbke}URAy7Fed3Rn*fi+>++gQ5CwG0^lGHuh4-(;lRjShtaxw^tH z$;BCYsr*%3b#=TH7tmUU@~Kv&6U++E5Ez-VB~+B%oJNv3PR@fnFY&6cVC>!=`Cxou zZX~`iFQ7DQsdF}bwfg1d6O-5Ds!(-dYHDY3Tg6$)_s=SkD-t6kP|UyxVTJ9qPSAvlg9tV`7~5-zd#n&ef$S70s7L^Ov3A{aoMP*7Cf3 zS>&re+qnsifB8D^Vy58-Z|v6XP>c+XqbiwXm7L#{)ZXBH*g*qA^vz%P{^Avx?$>%&B}q!&8_g8Frp4 za|cG{6GNsEn+6oTsb^x&Q z_q*~_Raws?)mKl1;qWO^W3@dY`-{^=d0%^{?tZ)nB^JV_)qgd@YBHr9@uzYU7GT1_ zc~;e_crYsM4@Nz;w_WX>Vi;I^%e*<9qeB5|HPpHqT2LhQ(dJ&ue@;dh`tqsq*?sw7 z&*k>ge>H}4N@ePxOUJ4zoWDEoyRTq;ZRH940Oyq}2DHp!FFSt$o^oq0kRwm|$2e_K z-gbqyyum(YIQx_WaPYml+0D3A%O{g_@I1CT$MKf=HexOFz6bGg^>lGGZy9e(up0AB#XudhYOrM7TaT8p zfr*8A;H}yP?o#jpBnU1xkk9U}_}-j?Pu0G1Xz*TAZTCI{Q%*#;=;gsVnu*lMLlY%M z7TA?2;W+!2m{&ysOxQ$p1BdYPmd>=wIKd8$bk#QVBIc|$Grae?9I<3{Lo8LA@10(x z!t3-{WwLY)??{RHmQY zR=e%JY_*?nm)c54bjJ-QaKis8n&^pty`=T*u9@ny ztR-x;Ye%=c9MNsB<(++Wd512uemUmyZ0$OLB1o%;w+-$BUEr9ZJp+jdZ9!yL1flcB^AJ{Q4f=bI%_W9e!D~@a{pJ>}aWqR}Dw~4ZChx>ON6> zYUUIkl;`&KLj5S3!rLZ#u7roIc@;=99yHZ4rnL3It1z(E8Qx$lv)cHPqNXmtii!F65HEYxi?+Rm~TJ$Bvzz-QfvE}&Q0eUJ>*D z^(MPl@F+I&vd&rKn1hIdxoY#QhJ}d%E&JqFo+=$x=6%|ZWP-;iC_B&l+|{H>34IgC z6?hWI1##*Rvz!o)q<9wd{e)>7Uppzqn`|o$&M{BNQo~lh51u;*txWe%WZrhV*sm5~ zCdgeEyJ1)_Q_~t{q(rU9j}dP4!`~s?;D@&pzG>F91+fyuV!Np2r`uh37|*`yb4+oz zj84@0EK8iLHBmy9+WB;NKR?qVZRYyb|Ah^Us_)yes;~Nk_MYL|8?GefSJG=6`!3&Y z-_($uww=rB$MgDXNZ;kV@fwj6^jx>&wHM*?jTx^a;t1QOQyeWi$3!bpNoc&zJHt>3 zcjZ*S`Zr>{GX42J@z!j*{5eZ?uY^H=!XGdHuh4tJnc3jgXgYV<-DKEfqO`TQz}UtJTRk*H z_Z3>8Fj0afml%v&q?H*@mV9^XDmh+7B&6oV6gE0V*n0_=m0!B?nuvEcxF7%|rn2*C zjW0)#P(h#~BXr9IS^8R&CBsofEl0mhQQuNg$}oa@42_Z^zUHH*;_G^Sb$Jv!+{ONz zVpVF9n&mT66`XPB3@@=-o1ri-C7yI|Iz_HMO3IR&jq7nD{~ZPQ--s8TaS)SvQ4 z*>vFfxk7KLV+i57e`T*VxcT_y@O<CsXgatH}hoIn7mdHNqBc@6&2Wb>DtuVJe92b9K zf+(Kvy1BA7QIu0&c%ffQo_G3jR*NQ`VbFyWSln3QYg*a-`s#e}w<&s}3+o%H)~57f zP02Xp9lRYRE|Dx7n~05ViI%TKIP=b-Ds5h?N0KtWM^GmHlmgzQ_p<-B!dtQnPFlf< zlCeF{UI~oII4KE7{aR!*hjvoFHriaXI>j!@}DmdXvFlSJ8ZAUQV8rul`IXqZ* z%dQop}_(PkU0xOlt zk$8Fv>{-53mH2z4yDH0}a7Blw$>z zvhvNfsQG?WJ=Y7kk84Zw*OV-_k4w@YD^x@I^})(^m&Fawf!Uugy$qtA7ZgWZo0eev6x4zan>%x=kFKVb9B z0><5XjAIn({OpYy_bhPKl0ll z{&`I6g~{_jN2eiD2?ThF&&cZ;k=Yl2KX$IA;~w2e#TiC)g?j07Y9Yq*_89U)=Z_Jc zXDJmd=0fyrJqX4ZDM>F<*HL8BV?;m3TXLDK$RedXSOLOa`*jRNy&}?&^1T%l9xild zFNIPb;}r{!S0j_s$$N)taINiC-gB$md9q+>lJ84PYx~pE+Wxe(rno>_+wV(jGjsNl zGww}{c@4N;D7>5}FRma^@JLAq-VRQ>YfqRQ6^K>C7UlSY)v!OcAy^G(-H>3VzhWv{ z+nUFDOSPTvvX)4kWi7b^Q57pM7kriOL6P@ z7qxXK>J}+Tx-`ufe&)Z8Pp^@h9sWCBAO5HL_^+JHa0JrJn)zDWodC1CP(K10Cis#O zV_b}rWH#ie6q>xMc?(15efMvOMH=4G-kKuUEzNViHQKr>c7<2vf~%S(XLxtouk`6g zn-_jRO_HJVHTF|aM9|m#bn-%ntSo_?5T2@Em%^<#l-&3V?}9nK5B6k_Tb!__cmNiO0zPb&8s4m_obN-!{TIf#rq zKE%U~@OyQC0lok|O^cc@IS$jl(j>Bddq@?e4`qx9U_k<2zdEaDbM0+q{28JW_ zQ?5a0u#e``_}Ybu>hqZ?sgxj1E*zL?^_JhZk;qy4eCmIX-+*Hiru!NX7By||7fZ?D zf{*>ZEo(J;QtHSaDWV_c`U!lJYm8+maa(D?a=tuoti&nAVA;z)rjhJ^@vyEq$jm2#a zmEI)d{?r$LRU1!x_;IMIHmu73^t!9EgWaR1K~GBge$*Flp6Ffj`%IOKCR3kD1mn|H z@-sa7?(d`4pm%+Hb!G+bRzLU+jQ#2Uoo$V+0Uy~ovo~&o`>wVh?e*8Ona8JVJ+*ur z9D&N-wS~ViuQ*-1MTA?v=B>T=cc$eo)DL{T;q27Y?N^&)Ud`{iZGYdD_oKde^91j0 z&!wvzx@Zzr#=Qx=ageT+pW#-2>a_m0+Ul3W%loUb0Tj_O!ccCePw_B9RR_CVBD#ryfJI!OVvZmf~$Z@OQ9F*FOCg z>)Ph8+5J#BH)xoU#2+TU=LMlFLBGMjjb8d(k4v=HKrtmnW3UaGF9e4J)rV$xPrc-3 z3l}tId^UcKn}j%H?>4sn)xQq`E4{!oWZ0|{Wko4l?=^(p0d4UlvXsp5cK*_^3F9)u z$E7DOo$1uR=C6}aCQ9Jb>od5pVC?@T^b>NBg6=pnDnd!$9(of~fEZ?!M!Uc|BT zk3jfN{;R9uA<6U(J0t&Texs)2?Cp!jcsko#?9)}26V-&uE~h-uM@nyBWl?O4N64Q=XbuswrLqpJ{VREQP(XMLZzHwefosH`c#<}j zS6r6o57?wdnflJ{zP|Ia>$6mu`pPLFT;Jc=0{iu?w*gZ}FkrtWzK8k$dPk%${v<9a zHw0Goi(k&P;S)u}6l51#_(`4#mpd_asn z&0njp%+(k3Dp)`P$s|d+ooWvQ)`2^D+dYaQ{7?AK=oJAM{$@UKw6g-VdJlbrAk= zFMVz0-4&E~>aViPdt2}2`SNmCe`=$dGlDW7Z$vTgKVy0QqB(~5i_~MAqt;|)>zK;? z1OE^?>m6*{ejV|?KG@cW({#k7bzvgM&-dMQJ~>fWI((6h$Gk=aKHNMtSXvy7B=sGN%AqxG^wh)DGC$U4{ogs*kA)wJY zgkKAd_DWB8Y1bfnD*kns@lRvYwc{ucd(ps$LiWAQx&CZFgdcBBeK)f`!6HFAAu4Oxkp5aH2$TV&n(eOMg?nGBE2L3Xyf&V zRJ9UY2fyR#Hcm?yRDXpQ2c7=lU)nm$^KX~VV%OfLL4&r@7Aja`rT&;6qRFn;k{i`` ziH);?<~35SP=L%JG(yN58jE*gO;IylDc&pW>J|MF@j!pUQth3?a_y90K9mJ z#BW(0Sz1mHMSO<{pC+1Tpf%upPojE0)%*TGD*uzDNm`_vWxGDgEPFdz*Y3T>FUF~6 zRoynIj3uF%`X#3ooE4FyX)RghA3lO`D`Abd)(4NUdQ4|HKBKf!n+w$`ok z!LQosM6LElXga995BcOF^KR55xZ(Pr?XsB7>aG5s+GlP(Wv+YBWy<5sbh)q9lvq7h&GvN?Lk&Y_=YK}PGugY zQi4)?4&+HNKhddAiMjBzqvhQ3wQH&elceBL|7xUyN9=cuO(Tk>4sXg~zp4ICcrEgs zTOot~JJ!F}-xGKy$K=!fys1!=f@Aj}pT-yFZtwSdO@}WwV%5f5CcHZ5ix$87X$bbt1Rz;~j|&L-d8KIJiGPAFiu>WvPwA zWkz}VpV`oACx9L{=KbSI_3ZGL3(}?KlTsOG1hVvsbcWKxGVf{2Fv9W8!}r2B|Hzhc zcIM1$9`+Zm%A>bnmM6*KfN7j>yt0+#foyWxecU@mHR6>;goUxfg@hL@uZY|+@Ad_e z`M16{0s9yS*v7Yk-ZTAwo4q*d53aBO$A-gY#OIKNOIY8^A9ZZOBY5-9OtsJOwlEc3 zkF-=L_6ndKfX4XC+dyBAp zl;P4j1@C4|Rl%OV*5PwE5+(R_@k0-~&C2h^{^j(!%eABkBD`jfxo9hA zLOF>SuNo1l7$y_SzL7GaM7dbtFm4E9xsODPxIYAo(!n7-oy(1`SXhKv=dg8LnuI)c z8={}IWw@~yB8yW)L{3o(6O632P|GDced6-1clpNmC!d=X`Ee#iJ^N~#6z=7o=Ws4q zRi{pcAbyYNC4v|cvHL`eNWX>op-#A%usTN_IF>NC3*Nf8V!_hLoeS?chA9)GrehB> z{_I~ShxadSpawPI-(45JPPSYB?iwS{%OrC~TTNlzgmhp7MSx-4hmpAI=?*^zq5h9CLb5E?+_>Uu0~EMWs%=D5mErxf$I?}8CYq`&`un6#rPe6F_wnqi6zM(s$F|Ov zf~0ke6eJdKKZ~swsxETB0^Glb>qfz&G2%;hyWx$hdVFKSg!y%~eQY#wQjLK!{57x3XgAWz6vOf%RAL6gh zsVJ6O5s7)e+lwTsV^kC0Bj}Tsf+DS<8DjORzxkWuECDW7UPvZ(TPqQio{VEmgzRH#W-vM{o6+&@ba=!22}fAq6kpIXA}(>P|MlYds%XgGXX zxO@4>#D~jd{z0Z`?P%*<6a6isP_ks~V~lX*w#V7CPS2Swm#KGBE;8$Hky*#OB=Nno z%gCo=X))yYSa}f#hur+v=H~KUnj1wfEoUodcnjEY6g*O^*Y18n>F!IxBM($jSM`qz zs=ptOT;U>D?@%Pz75_ZQT>S;2e08T#H9X{smB-Fl*Y(G|U)vS~oo9pej48oHYCkYI zpSMvzNPdVva1Q97)tF_DpR8@bM5+!b4QO(sLNgq;-uGC1+|*N6?>B6t1NCJ}b$d?} zlg()Iw9KxhW4riN`?pW6MtOTId#*Q=lpQ@?`rjdYKqH+kd8aDt_{dT38@cWHA6Y~f zP4<5O1NEnWcGmCm;H<|e975e8+7_;w((!x$XFZmKZjOG~ArNTzMOXCR6&w zEiNedITouoIf}{(9tj>pa$hGrt4@)BU)DimcgonhG3bz|*6`{$VG<3}hw7ESW%ZRP8pKHi1{siTh%BgUo=2K@(W($`NN!;!gO zJ9YG-zy33ZBk6Z1&*7pa+k(_On*1{2SNAiV{_OTXPUFj8^2@Umw&C(-yteYn0{rHO z3mep9VNgb|_~lTZ-3D-*T3s@hLl?;@V-r$<=vUde_>}^H9eg}#yt%cKMZBLuX^0Q22n@E`L+VSti^dEH_ zkA{FFb)yfx-9*9m(@5gK|C_B3UC#t`BH@t@h=lvuaL$&7IIRzT86nZ(!+Iad-I&pb z77~69`cU}k8Q%%5C%y91toyRulJa@kdwk>a2=+EUFD;*si#9uF*(6!Lxn$);_v`zx z;8^(zzLsycB-{15C$$yP=Y&E6!$dzG^`6K6S^WPuh<2g_zQKRj!*1M4n-zMO*b@jyPI*2K9s3!0V8udL{H8 zJ{tWufr8P0Q%xShfc{Npa91vL5Y5e2V*NC!%v-fb&RgaJUQoSS-#CSWqtHdRMMKZc zF_n%)^(b|>j>U0dU`Kq9esa&1y96cRCXzB$dLYifHLOy}*G{KC+A6&PFBhVu?1+`? z&I}g!EQQc|R4E9mHWQjCjoDYFsMoTFhr7!9r?>U76cwn{MI0`e{)7fzjpt3oNadO3 z+a8$9o|G@&hZ*q&R*FYap1TRtI!FvO)Ir8sD?Z#yJGULyrZrkfQRn-8{y&fSg;$L5 zW461P8ryLnh>U+~VIsef*A( zD?7Za6z5IgC?hI`Fay2P)!xUsoS@D9!)LU^C+6J^^LD&Jwx2A79$|A5^S;6&*9D=6 z*~a#pj>GtLxh~R4KVLAzP3C61DZ@?RjA^gz6YkyCbz{9NexqKrJ9v^;qZBFhR_yot zb?n+%!`D0@jfzXVcGieBrgaH^j$HG=y?iZ?0oah6$jwtEW#0E}rv_*BpNy3IKP!ae z7~ygFA0$aN`xp;U2Lt2(wf@j0pwJ`oPHjygG!|&Ebe_hT+!}~Mv|-o%b<9Zmol*=6 zX)bq}xQ<(cC6wQVXyjBz;%|B0u7~ATXRh`7`RFqm%@l^vbX1iL@$G>xYrFR=R#J9F9c>zw zN-2-`DQ(bY#~amI$&EfoHP8%^nU`MQM}FGdQfBjHEQ&OZAy2jxXvPeF($|+&p5i7k zH}fHEI1|sA&VWR^T}HZpKcNTYow~5R zBWr_Jzdh6GvYK~h=%WXf%!lC_5CWabi#+w!>(SAX$0TEghY?Pu6v9{PsI|<`Sg`v2 zn8Tlp{#GPq`@va32Xbp%ct4nL)AJ#lBJRl5JIInO8I8Y3a_Z=;n{1L2wW4|TlSd07 zO3w-EH`z7!M7eqXG(BlEiqh3_N8Gk|Mz1=AmCVGV{z0tRC3X^$x_~TS*)p``90QY zF79hCPE{1FKG*do*WHYh+Wb`alcDl{4SSL9+qrld9a(?Zz>8RA64kzfnh{65(htAC z74-J7vkCg!B0lqUZ~ZOpbhy9u+wX6&xIC5!uU@*+eV**`thaf|YesvM;94|KrpNZg zS8K_Xs@@Ki9H}hdVXGM)j~U4ydH;ou5|5Zrs%yS4)Yd6?O7Y(F{~-gV3i5tNu=xO? zZWNWebqZLFztPQ$iw>zbe@g-chVKo7{SH zI(sLqH&eSV7elpNG=9(LAsBZbvsq2#Er=Oz!5Gl;RcfGu2&Ui91){q!W4s>MzLxRo zuh&?n|Eztrl+s21box)`OL@`Tkw{P}`a78q)oZR~J-9N>uf5O1QB-U7Z3+Cvny_lt ztf6*a!thrR-mG$R#z-L$cxX6((QngDu%vo3c9WBfMsac}3j2hf_$%w?<4tyNS>k{4 zey};{%kv~*jfBgo$TIJDC}0y-UVM-2tQ?3*+D|!lDQWPQieB-Sc;}o4JBR7rOV;dZ zOj#*Ub6hT`-8;MumDV5O5T@O8j$L{GBR!T{&zPO0TqdtE=OV2n5Bxtn2&2bZaL1c) zdAeKAhwKdL1B<9%>v`3d8m+}$hvFz_nj}n%cj$CE!eM&{N9Rs6e+$FKcV{B%dWYDcVsSDJP_3SyPK z|7{p1qdORQSYfbSQNSmpSg=Spkh{LYK%R>r-@R^f!fuV}NXIwdO=TL>e7WRBYRTEe zqMc9pH-vW+9zpmJ;e~fDo{y*AvUzWyt}-*Ldk*zF-ygy_ z1U>VbUdt~_m!Hv$oOpB%?VMOp4gKaP{{FVx{oAjY+^$XBoa*ziPn&Xz+e)N(SXOy{ zR~~nF_`6*+PFJkbl8Tr85c1q53NjrJtUSC4yX+WHw?T6AaanjiY7I8|dNTA<^DYRc zmnm6qi#%!k3v&O6q-D3pO2NKuYkEq$3DP-irej$TATb0-tXBVs+`;!b?)zQ#eV3;B z7JO+F(QONHw%s+gG!h}O#g2KMl!$(r6GUk9_MVg|{l=n`Z?UszO^?}JII-0p(vXOhp8O5ozbkXpe=uX`x0v~3*nf9F^WVKo zGk>L<`ID)_(dZ zu&ze#{Jj$2LAsALKJncp)0J`JG@*?~xyvHqlVqJY?8|AAj8}OPys!QAKH+s>>S3Hb zD4>b5z3V?KLfTI->3fWn)_Ic1B zlQIXRy=4cZeK|DP{b)~Ti^16qH`+6(!i_e+BiqPX=a2PH!b=yt2@AJBfNs2oJRDlT z8v@BjF+Y9~Ru8|9sw1$$SbA+09$BhiqP2BHKxYG4Bj|28m2gv@Rm` zU+|!rnEw0-4X2m-uB5L9lp|+raLOxIUK2^Bl%dS4M7@kM|OPe(ss3^x?OYTB+}n+xpMmbORvRlS6Q_#Kf?tit9KYk@t2g9_rG<*WOaT=#v|n<(8b zLftNNzQcY$LK(v1?Lle>}sA z)Gc4*pDJUqs`I`D>xy;G%A@m#kTXQPgQ<;oqcYmXKcF!+`Py@W=(LBS=gm-f_YCTr z4~d>vFg$E79wKiRJx?cdK+lT_t4F2vnooFH<&q_LF0J@KvnGYe|EM7IVO47zh}({( zA$-8Zk@_F7&jhj=V_yWh_{9DNeBwmx$I(R^rNRs)-S2;TmV*6Vc73#oAL)cXZGDi0 z?0n)?O(>ck@V_@vkk30Wv+qvtI8T-6o4>T3Vc!lSg>q=6IByv@Y#(HiYIP^k_QC_T zuXSQ&i{#6HQ~8!UAw|2D<+H>CPjw-dS|TK!h6!l9AE&Yg8?I@peV}Xpl`d@{&Z>tY zqeaAujQ)8>R>$vt6y|s3*fLEX&e!_(7?|}clE@>PG`>jk>*r|!eV3mZqm4*(;q~o) zL=2zbNhB#)z1RrE-X>x-@yI#O?Ik~KId}Q&P`4dyx7!Z36DW@EDoFi~def`pW?LOQ zzh&df^-Ok}q}pO(4ve}tBVBTiO0L%Nx%eKzNWmvIQdZKUxU4XhQa*$tUDe=CU2mxg zqLT$CHm(DjbX~2Gahls$`J8lZdA2`>X(hM34LeE7&W?CTKAA41+Dfs!WEp^bOew~@ z&P|uHk0@^;r8EzMclayAqTH0R*RA^a%}jwQE6|Fez=26a5TU=$JBZBX(6T(kC@>fw zpSE8@1`C$^w=*_LJLF-@y~Z}gG7r`8HCXQFJ_dWNVmIDBdtA3&?6Cq`g04TMt%mI| zS^gvC;d>uQoT zwd;)X^>15XN@;qQdMf5!KtE>b-|DLm@qsenmCpAZ#X9ZIkqZjs%*8!EaKqMV&Mwq5oOk&ZeI(z%|pL^`>V^`f1v zq*seXBaMWmKNRg8BrH4>-bZ-;JyRPG_r> zi0({AcP6SEwT&y?X_uz%jPKFUPMHK{8UYD22`a3j<9jSrf#rLr6<@;Gs=&!8XG|Ka zI9;+V+m7gAQ}}Ig)ba@5TSjI+DbGc$0Cu69<3&3##(_9ixl%&bYXxgwU0^xg@(35dewEdP!)-(4Njqz9x?@6pDUA%6q>FS?g+ zyBbFZ(lkxLgNf*&M6@xjkjHw67jGiUnRLmQc%RK=&DC+!wueS~o8fKapBfx(AAG=( z_4>V#b@bsZj(5{nMa#YrxPXmGnwB+9H<9BY-8YKxR>JozoOdi&G-Qpr(O(7P1}PCe=gzS6=ZbV%a%u&PSQIxkuTxz=!Nx1M> zXOyU{yo7a#OFanB@c!^Mw?X&|S+P-!fVwNpx->jlt<+pkySKS;)pIHw2Z4o&6YWas zVd<~IC(c*$sVGvB&X^y{SY%&$fhV0YKgc+oPc2Kc>nsdqJ-W^`I!D)86v}vXokig~ z>C>FG(N`QnYkOt>5M$ z)M%`2$CYn0{hB509JVig1=udWQ(pB}%1c%M#n52oYb(4ZB2VIW?=vLeR30D3*E)l!f76|ZWG}TFr z=J84mGs%mr*I2fbzMUx~o)JN*xa8LPi{H%Abn?Z2h2@LaVgHcan5}FWjl39EHVi}f z@P*{=?H{;)F?JdI$4X7TuJ#Y4%fSA@-Xy3puzyfQuz&s?)%9ZkQ08F&yyYoI>T*=~ z-HW%=zo0=2>>pI&22EqOjhw;$c_-mF+5WMr)wlQJpL*2$BTnk`WS@~^obwia3HHH) zF6%F@8*VwCuTW^!K<=orxcf(Su!Bmj>ampluSox zME^z7#FRO16D_tQ%s>C}5Qa#g_b|(COQ_|~QjAAf3%vYvEt@dsTDFt?Hh7mN*~S&x z{?4_^y8@lI|2198AGQWw#8&8CEXFbKDqNJ(DK1qD#GU*HNj`(wC%|&kYV`=$xEw+& z=F}7Jwij=}M>Rl&=?S-~wj!nqX^i6&6E@@tUB%fRi zgFH%eV>nLg4)sr9r0{Rl8V8+;d-Q%n&ZD2zdHwZlbNu|wM??CJ&D3JMi{aE*b17AJ zmF|vGacsjhqpj6`ZV>CT!NUE)&Z1#?aRMR{iXSBi46qntgI8fX4*Pdie zDTE4lIcRv#t~E6%hwquTl<_DN82@*aON$1iqP4M9Y6Gdg?a;g{Drwmhso6xEj&`F$ zs8lz5i+|?I^7A~+?%EY9%Pr{pRUS{@J2TepR;xqgJyvm1sNyB6czjP4qsw&_yXFYL%_b)$P9h7KX##bRkw4daV(Q3*D)!()KeQCpyU_52Uz*)-?*vv~|v4N(pw} zwC_kQG+=3*Oi|LnjC=4uds?Z!{Ao?TZHzjceH(%#^z($|i5U6z)A?r-{sdv^U=+WW z@Mgl&$E+qS928zj_@;_GBR4Hvdgtx7sx7?p|L#n6^W5gEzdm+Z9&79^*r%VOLv%r& zPMoC=aO9Xl^kd)FH|_-+1!qE?+c|8B+ojyB4>~9@TC#?n3Br^#&}7mp_07fVu|OWJ z(Mc6fo95YN&hJQZ0M?#M18FZ%P8a^$^js9V6f1&<4F~`CV`ec4# z{?_gJUQ>c?!aT!vZY0ZuH6Q=p*+|!iZC52*?iBDsz`l?~qm)S9Fg9L08$!<{8sQS5 zF%$2jH`2UMeDLVg!L0~mqTN0l5lUd~siinLUidtjHRAvaBV&($vfT!A{im`ozFpz! z>y_79`E{=RR8=?n!rNUP@utE+H5f4YKux&zD1G3-epKwYk@`80a(kG+%lFb&rwuj3 zL99>a{zDmmjCD77)2q|0+i~Is?_KPrV%|VRA~Deh?`1e)Sb(?=0|;!t!TZn(m6> z-oR2T3rs7B-MFYe@>zInOE_YQ(1`xc6y<6$tJe!(ccb&h+28w|zyI}w$Xz|!Ic$wv zqvwN#FSKb62VK|md>-$k-4CJ7&FAlj=kv7Se#bW5?>L3(`kc}oX3>!}#`_1W(oL-tFWzF*UFKa1%jZ0~^FMsolhx0HS&n%j zQ2H0x{D-*dC-}M6QZ#>ySt#7^q}*hiFj+vTxNX@Ihyj0M#hiAVaI3sg>8|3dMK*6p zHwu2E{thOM!ju|Wn^I^^sva01Qk0FzAVWk6T1G!v{as}YQog{>JB0Et`MK6o_zS=< zSpb%@j&-lfS(VfR5ObFeew=-{Br5c8l7%bC8u0(^gts%{B@2Ipuqa-8)~^v3jVipA zF#A{jzmU6+LxRZvPlJ7~SEWb+Pe%Wi6CCDZF=#a>A~}tnu5Gdu9!4`m(Wr0WI8wQb(CV zZMm+tmYM*g6H>wsmrn{CMqv``Og@OfSP-=oe-4Gmyd4k16sopIDnru|=h;Z8!2tan z#_W?!ckdI8IN~pHOK)d*+ybNv*KLXW;4LnWB`%jZ8{}(9ha(XDsLab(9xZVj_~|0O zNen?x?-N}_cZ)niZ}vbQS1u5(6;v1SHNCLA*NZM>)DRhDqwDGQqDxHaQU_T_3aWoV z?*t9M6P1tYK-13|?FUQmspXO|g>W(@m@wZti7U>zZwASUj(L;USlt}!wX}kX)EXdZ z2P8Kt#0@=qOKH_!y+7pbLbrlvj41wBtV}90l~P&WH`q_uT4L`yd7tN}Qpp85kX3|r zSWvkMWe(oY--YNk1FJVvPG||5O%X|pbkyJa9Mu0Omcj0qpnsrwT~)UnN6h%nlETOn89ub}On7l+PB* zhD3aip>pqKs;@AHqkKw59x&9M; zPFo!39)|KNk(_5|^zom(U*x7?fZR4JwHbSS->hsoN7@K5;(CYA!1pk~l)G zRzs><8LW(iYq1m&i{UFfndWtnjBbqt$-L}j`V=H%q|(V6>!UJ2;Pg|cKO(~Nl>`=X zNLBYSIMaFhH1;E?T{1!k?}d;Q*9smuxKz4lodVniZLV{g%{7*~4wg1BT38&dTZTN= zVDeali$j!Ajr<^EgL!S+ior}-?23q55gbmDsG)C-q}(p`pi_{ZYu~rTt8n?@#a`<=Da$T%oip&3~ z(mmOKf_(mj1bHs9p#N2OE?ucjm?@y`MicLj8!YkK=%2!xmGzsfcly+=f*<Z>e)+>DLZ8VF!|DB7xwy$G+V3|RsZ}#YU%TA6Cl?i1 z$_*rP1l5Pkcr2f7{Cl%6p7D?^iRXg@W=8He1jF$AQj>QEhS=#ZFe6s1^Jhf*KGpyH zv_m`3=D|!7iPz(v7MV-oQv{t{w;Dh!O+6&d8m(6pBggj zpSi5@@PGUb=7M_7XmIxhh|Cmu2?30E);kNT$4DZW?@Sf(+M<|qdoA4>R2GFi>#rtZ^Ixej;C@z) zO;x!H`yB9`ptwRSqcFRSK`P@BA-yDwbQ}1Ud7oxHyCOZGA$Ld*jGP71D;&~$kTwnJ zd?bH0u5PQ3G?z|OcH05`Dms!^ z7bbE~%OILn}sx@HawKaNGY*k^2>`}WH7 zkVEN^o|hS`uQ&U~8B_)1W4MEpiB6B=j@op&)$_3j*kamspYTZU3W(5u@c9SYIA^Zf zJOS;KZX;-!W-d5;n}mG9qeVG*;G8E9_YNLE@w0w1E311eTAy3&)o6uSGQvyi#ULRf z=+E^XeGaPiPc5i+EB}5|!+`wzcJDH5t6>JagMsJ|C5FeltG(QvfB1&#a4Sxk_e}`g zT^qvY{(jJ6n-*)Et2HV7?Dj>}UZZgsvoGG9gV30d<5Wp{19u9aO(K17-~p9>42tr0 zQXWUA+;sGi@DRA)Diq2O@x>o^o}0XJrp8n(B200Ql0gmc+m)@)zE^^9|MWZ`mdoHH z9#ImhxR$_^lc&=&HbY8S27FI}5kjqf(ZJ4O+g#%YTSPjUFA2Z&2`j9AatZzGR!x64 z{Ze0gn@vYI$?!ky=qFXxSi{?!!P@EUhkG!~X81J5P*vhVgWJMIe+A5dJ)^yKDdmwju~vDTR|1rOjeeDtcW8}wtsl&Ay2I3+ zl_&XeXFh6iVPyG|oYgeu0p%ZG8$-useK+5#3i?jB=S^K=ULy~)cym}fUdtK$yo7bF z)xU}S#;(CkVSnioajTpV zESptUBOCO{Dvy3oI(~Z?hhFQS*KPgxb*X<)Z}nUGjSP`A&Q*tNFj}SOue~Y#cayZ_ zV;Fy`Q!h$it*f({IQMbQ9`AyUMPiQc5#%mMxKBi$m6Goo3E$nNgnmI`8& zlJgJpHr^@(ppg%gsK=fk6S+ zFXvCpYcBWGPUmMbC1~v!cZW<1O5-g@U*I(6D&D(Q>H{1>C(oxL?&=g;s^#F7e|KL( zONLi(56CDbdE81}#@9T~A$p!U);~ofi6` zD~e?$NB0!d2g`#Sb*#WcY?|5kSy=XunD;Gg8ZG5Yy1ZgQw|TaP^5j{bugoXU1ea%E zJSi^P@#LYu4 z?d1)u6C#>>{*ywj;&PU{j1v4A*U!E;`z3y9qh^c5xMfJU=4;I9WK$|CYy)7iyimyR zmNClp(Q>o&Y0!hj3R~ih3MDow@mkBWrurtrX}d?AH`{_KxVd0$aCg}kdLKh{@b9;GZ-k6T305}l`lm6T zj-#$%m}<^uoWlAULt&Po;HukvtI%*A2l|`qSX9pYUD2sGRm}veOIojtSPm#Sin!jv5HH?uexmD5_TU3G_UI)_+ zmv9M0r3Xz^+?TFy*1j2Ljf8C?KY>C%k94GRuOU?AhrF*ZPvda1;ZQ`?cr6+-!^f1i zURJuh;Ny-zwGJd+S`n-HUaNVB)x5)M-U^1v(ybQW1QxWJaPh3Icb{ZhNTs@LR^i=9 znY@*Hl^}oW!~TK@o`<}x^vdn z8D4V`2i}U_&16+E(0 z(fr;`Q5{|z6WYi~1i=I!17Ft!f8*TuUiVBhdiC`U-Rj$oShsy1#A#3tD>wTP#;iEn zdJm)G=y%9cm~>IWqplkmbURe_9hMkty^5#x?^@+re@uFS{>|q+@S}QR-n;i%>Qcm)~{#ilzjkI@Ke;%X~liyowq`>!i zqmwEx$4uqxw^;T4o7quF^CFQ`68!F7r^Uj>H@8d!n|>{49L$zc4_?dBPkSv#^1a$6 z>C^;&!oe2cIB1xybFeA)_kcnWij`NkTaaJ#JhS%prf(>PMAPjR>rLNJ_IIpW67KXs zK$lC%qWSD^r1Iujrw*s>eumVhBG8rh#&4mmR!Z}4BKx*|_irlu4DAb;7JKO#-UrZQ zIW|8qnjdJ8>vIc9XT+s~{NtnxDM-Ya=kB|^-hQeoEm57r3SIPMqTvyh@a7H`(sFJ{ zReX-&V)_ad-0oU1gxIV@#Ya}CN!fRpc`i&D7steWC91k;H(0rUc=hKz^cRW>^AiV;>-7`eNAD-?b1N{NEaEar`Jctob3{b%G2DSr&W8;OY)O&m!FEh5;G^V@*@|p;MnrV z#aE|YBigAv5vAoT(9nREpJfv2ij#E0wyS$i7z-z?KPqAQ9CyYu<|R*RUcLJetRQ?UfVst@bz>&`R^!)3aM2Gb``FU&s7_$8$U; zL9Q)?a`t(N&Zo2-iFckWujN}b>{%K(pyjj-8Uxa3G*`g#-3Dw<9&6v-Y}`YB5$kW% z+NV)rEI&>0jQ;jeS?z z|4|p%FGZ*_R(?Q$!ZxH)%h5Ci^wK4B5KKfGMXRp(+qiy;?MX@lZ>6pB>5Yth(bNQd_L7*KI_()>ov|H8hfT`)Qk*FtS+<7c9}gK|S{ zd9hk;QDn=c9t(Peob}bMK5n7h4_j`1a5H7YU}nnn+j>$}eE7qfG$SBBCe1uyXYAPb zncGa}Kvz*iIJh5qCtsP5MbMSvKZi*a_@lHDenb6Ho=Z^`!o#8g-f5r} zUeVS=$r{kU98mh~k1Fb*KXh{-{UKMs?Ect-t<&{K>k#^*k!|&CIcBE&<2WA^=bzI~ zqM$z_C%wV_alkA?^aqR%w8H(dk}d5U(jT`|2mLYJ^@q$A+5NE|o2ToKBQ($3|Bhw3;UwI?xt(6^4_0ipAo&E>z&6m4Ug}ZCC4zn8-n}5 zbgNWNH7)2tgp<`My+Yc>re4AIww~HcH*DAQ3netQ`)?50{ndpdr z)c%O~%AL|pYW3Tw0#OmHajAdJhw-(Jbfyi3bRJ+wZ&S%VF7(Y=;@3hQe*F-M)BIX| zW;!`kp3ZE|Cj3U}j%_?7RM`H$u12@K_t04%NPttjTs0B9Uzd|FPXE(dlEVJA=hfYmJps-QSmQXkBvTj{?o1hh+RrCkz+O5 z22LJjbJkbdwPGxxQ9V0P!616&2hSnlz&D8&CzJ%+45uvO`9V^a|G#L{dZiH13!L%r;8mG|BW_EzNiE`yFo=El7L z4yDDJWD^C3ojF?e7{}!(Uu&e|%w%P2{7Jcg#IeX0Q`eX_P)V5Qj$N&9&N=IaRLCFY zWJ78xZ8oHujzX#_QgOb^VD2R`@5)fxUXdavNHt}U`cHQB-65strSch zjWE+(2e3sLed{5*TRY#3IOZSw)rRnXbsfIWqQ*TsYF2X!WYBd%2<=v#5_n=fw2s;x zW?udKjsK=sR~-`K5jhv@Hi+@Dub=_-h$GtGl?#8}n|5u^DYs0xlfo9QL z`JTGhuj3EJ;Okoaly=+xZ3nW3gggBVniXtEUFvf%#<^GO{h@Ly<;*y}urLsoC%=^y z@QZV_0%jjiNS3yZf7<)jbS;LPpgd;DPI9?f;_T`r1=IdXV&iT-HQ* z*{yFZsr4!k9l+uuKCoz%cLK)Qu*k6z;j%wt+-v!Fx$=FV9ADr5A!>{-FXz$CU3y-$ zF4h$+p#Z=ea@FJU`O)hnh>RZ1%AU$227rRyXee34lD26l?yVr?c@G0yip62 z`8maB_r@5znH;r4{*HS}}-U zEx9ev`UX~iklyMr>_wvQZ9EKzA*N;)=MpA(AG7vhKMG^QQYimqE=$jAX#|fjFWWTN z`luHSvZbUjKHctL#@$WFEJt#b|G{nVaev?WHvVQSJDE&BUzXjDgyP^hNH@IyP&ZN$wf5Mmt8IBg+B3d?MIrm%I_JIjZYSRj_60-R-YV5 zSUlq_}TH`t0v()hVMxNc`l3+0w{Q5dwRrU@O0tet~|%_TVup z_JGVsPFyJSiV(r+>+mA@F;{eN9T~>It9)g3+-`N~3QRncSRZb`K*x`RYvn%bs+VtH zo;QO}Zm0*e%)$Ak^~$-C@->)sF+8>5C{x~c1z}u1cAITy(C(MhK=U%0gL$#K=h}7RC_4wM#t^D`#;PN0}x3Zp3^kQ#K4Ol?0f9VhQe}#{Q z{LB5`r+3Cbl`Z;(9%nJOF$HqhD{Aa&CfTkAH?w@6^$}W(%YD{FydZEeEq@ z|5bHWC$m*piKu7tknb5YR(rdVZUeh z3wyd>Sl2h?>edDY=!soi-N0-clgIIuq!WQ$p*pQ5Fpl3YqWEQwYbWJk4hM$dII}3ioo<+Sax_weI_5ZNJ*t4 z)|n->>pG;<&H`uUu|au@F4SXQIY7)FdUro2HTM^0&zOsP`;0xIYax~|y%qKg#P0_axiqh*kq2x%g`Dwn0+hF~ z48hQ})X-ab(AkY)R~TVGoVCS0HO`G0c5wvoI{uF+v9a<^rb&|$o^Q2KG2`K0H^@=jXxp?M)qabDB^yO9SCnuO&bW( zeiD95=HnHp`1E|ZpOx#(#>k{Fi1TtZC)qOE>FK-7LH2)41XIJ?xaEX#52%8 z6CZHWq)FK;tDO9~b%1&YveP_|bG!h?Fu1>f4XA(Y=ocTvYJ_P&22{*G(Myw8+i!ih z&$;m4NQ2MR!c-DvheQiQ)|6V1lpO|@(`gUvlk3a8wG1ucO&|w1MM|zx5 z!cXZv-+k}*Pz<{$2>!O7EWMX*@4!|H-?LoM>W=YQK$v-@UE{Ohx{Yyq)$g%I09Q>0 zd=P&;*OYmluJK?1N4A!z&9*EQ@>!nkKQA>x1u}B`6m`EX)4XD2kk?!id}6a|q0SOM zN*dGZ0+;T^Rr-_6Acu~<`AMjKlR(JA#83AN_=4Z7itgVlyBJAYw0$)V$Ds9CmJc`4 zMK|vTnSsk`-QtM?m%I8C0XcSQC9Y%O0u}b30$f5={ib}vmJShKf%Ag!$o(-?yhi!v z+Vtx5Zd+3lf-Xs&E_flT z{%**Kn%`6q2Yq(!Nhf2kNpy_q6>>^y0GuLws{$YjXC^~ zo{^1bV@5_!N;V_skKv4%IO>I0=o!IS9rY+@%|{c`2Xa1=(My5cdl)#8T---WbEl|d zz##+K^@7N;KB>F7(KW#aM9p~)FdJF-zzZUhwZQtMuCcP(YJJh3HCpTGI;(vnIjvYj zC4Kyf&zWqz!b@c6@lt3!6+M=<3Qtz(0>?uu$*3FZ77EN-j8wC*aKpa_@wIpH9%yp+ zfl~I{pIab^P%8-?E~rKhPz-XD*!M)R1+4(4z77G<>d}sh1U>ra<@?a1e*5#rY{7?! zbZsB^*VAi7>UUTxxUnIJ_{~ZB#}g6futcR&diZ4LV;Zc9<}sJ@xjHdXljEgEjT+KytRe1a;6!v zFRj{ng<5g0dIx)>*0E@Ba?FbgKMwkVgM>>b=xW>b3U~*cX{5FjkOhlFSMs>M61cIW zlJ@X3$RYA3wx}j*F(7W@0|ijlU4~y>0aw=pwz?~_!#l#4=%(AGlb2fcC(G4 z>OojTdx_fNWzVo)t+vscmAr>dHwo%PVV_FM72GnZE2XU^Ou z_>Cuv|FO@>=$XhyLm&d#Y1l8R(?~1_SOAjx`jZE?3LfGJa}QRJF#S33L?W-z0bN>w zr=tqoMptOE13nU>T~itJT4N-E5G=~-NielSJjfJcMRtihQx^pR;ZHhcbIb-m?_y!K zi()7*YIcR!;1}&w;&#rQlYl5IzB-`D*ZN5zd=f`;FNrj$*2Puw4XK1VP!A}q4gjgL zF48L=%15EF!s?7anJ;q%d`3uE1!gk^_$)A{{hMt5gg+?(n=E_aA0ZQ3d*H7i4NMn0H|^yk5k3V$~9dYNw_ zuGqa|lu2&W#T1w&_(UzgNSHC#eQK`bW7=#8dRenQJTw-0!0N&NQ#FYO_IbrUvT8%6 z!=|V#vHcjn_@sFrd?IT$2~smB&03_Rv8Y9@?jp;O>s61NozBW|7&6F;GIogbvGVo- z854|M#ycLfi19+-U)}Hpj6F^pZY~!U^Wi77<5--NgoD5?)~#k81NTBQInJd6)Q4v= zPdkRF`ITVNumE)5!d-N$!tPog1z zc?7EiFVGe!%9TWYplBF0k$4vXUV1fT9h3quE7GQNsMxM%@l=@d3yOn zsU9kJso}Y-u?dP7KiOC@y5ye^ry+PPisATLc8PlI zXx0o|GwwO_3$bX*&W+iU?*b)U*+dwFeAE=89dR4cYo!7O)|!2I1=7>6n0?#y#h;(= zbTay>_dnW>VwX`X_}%_6E?IrDKDW_=Lu&QxNSP3$1^($5Vz=2@{j`y+exdg>Q9s$! zC}E5vnn#*>We^9D_scJ3H(cRY?3?^wvF7?4VeBH3{v?h!5HGL1Fil1u)1|ySk4Bd$ zshBR^e3*2p^F=H}y1Cp*RJ476UQn5vukGa%r|Cj;Fpl{Wf;LPAhw&@8Py{Z4u)6Jo z%&cvc7Cn1xT?w`VY$HA04?ZgU%cIu~I4{=JafB8tCOwTl~pyfn(cFJXn8IVu^uH6f3S#rSw$e7=Sn zI8Z>8r&=&uVxGuvK8=; z1=dg_tByTMmV!4J;wv>1Dl$8txdS{~f3q0f6J(5s3yr6(yH7eSlHdlOqHe#y~ zflc=(6T6QSiE?PT%|uy6?nEaOY*AF~Vn6-M6fAJY+p zK%Y}k;v%sC`FR}spNtU>Fdb;0+XP-e5P3}>8hXe43AP)=P?P={Uzmxyf9ZPlq&Gj} z>Upem-APv*Xei+P>W|G#oehlC*IW2r$_Rvb>4k*g1b+Mj^AjQ7!_;m(3UIn-1sHL~ z@nxADqvu#RCSB`&0v@PGFyJ1J%{1k2XTi@}0>)VBe*xyX|TipC;5-9d$7YdOawN>8!YTB$R(V(dK!VS z*m()sQb?YbwnlEy@-*t3v^*PmG_L{y!ChF5p)shPe!2W5$^}<56)0WT>{&Ca+4CSG z;;b6i>Yu%U@5&;?(hM)#CTw#o{_WARX2()d^s+ z$UChQC%1L1`q69Y|F+KUI}u<67p?P)QB7R^x5{|$fKTu!v_d*SATUiJ__j*QUHunA z#N1)M8H}3yS!ZxHhwFYev!HePh1R!+tZ#&Xe7o~R>)Rdj4dGRExgjH;e~=etmu?C} zCA&@rc&$~OaMM*^WPQ8P`bIeFs!z7QooH39%b{vt<3OwS%4jairc%QE=jT;zaQ}c;*d;NYUbHM2jd!gA88tDkopnI!B+6 z(6itsz453e5Gusq2t{jCAD;k>luyCc{G^%ENhM%P9|UiZ*hgUfP%@=$m=tI>e)2`V za^~CzS7OIxlx#z%h9mt=q-meV5je;FNUt*KRYF1{q=|h1(-xqqnyna9F%QPB(41M|iLI3~Lmw$Z#S`kNI{`9VXXQwZ}LOzSW z+{ZF;^raEJQyhIc5z3?kOkchRso(vSMPHtZp)b>|Z$e-AElOW5mTwk)c`6Zo$+L-9A)gY|Y0@TUSyx2^; zaSw?}?hcfy(Ty#hE#wk_?@Tw5Wx$DFreDTZgLTj*yXQ{*u&c$hk=swOc;mJ=GNI0d zJyZP&6h+r;z1|IvF7@Moy^GguCCEK`_lc8V+=TZhPJOXHP^@2f5Ay7W^fn0b=+QIW zaD*Ch$%+%d@aANcl~vP#{RPJvrD(*MHalNKS$ys4kY@|}mxqq6MS8)^rSlG?E>!O~ zKez8U5$koE{q~x^@|ls!MDzaEMD1nG({a`zITG}j1K+0@CEhcyf&`d%xqL@q_c^>% zr}mPP57)AmQ{98QBAiLCT877XhkYXj7l4@cC!F+yr`9Ju{sCKU{QRdHKeTyTD-0Dd zWiSydF~Fc!WWdnR&uY2#NGIPsubLa?(6ej&M{2_|Lko{3|6nN@ z`6q^#wS*w^yH-vxLm0x@fk3Dp;T0$c@D~k27-A|=TG!&K0SJ4W<-E$MW`7kPAPFtT z&$wp)E&6E|e$H$5&(=@V@N-tP|I7MmGJf)!{l)s}3jK4X{wc)Ijm`dv`e_V)7B&0N z(NFpKDQoth%BPSyLo*x?`i_l&KS$DR8G#@r&2|xT5kL$1*=oSwC26)2@OMa>Z3O%~ zCCwHB{#K-8gtWaFxCm);VMa4dltl8Pbd{Z_-+_seFeiLB5&1%)HWpLAeA6&d1fPDX zsty;enDj=3o>yUj#Tg`DRZVYY4r}Oy+$>HYHDNd2I_Q8>qhB!4Cjxa)utO=hl$_1T zS$w8Eh+qiY8R#EApm=i_7K2xvUpSHbhIeQoJV9Xt}Aff>XKc=hf;%$V>!}XTdRx z+)I2(4v&#gKJC2@W`$>f%s7g zW?AFLPv0@H;ChihSAto#V_zL?Er^W;=_rbQ?*cxV-WQwxhF}{4y`T-7 zCRwc|fL^}!jT9gbdM^2v7%UpjUWJl zP!s+}_LMgD)?uL2@+r8QpETbxZ6^2@A7uZ;T>Aqse64IM0-{1Ium;42TMzHSn}Ko` z&;EC$m!sRr<@g)YB+yJNq)8;1{xi}fl1#sbG>K$3(z}o*k>vZGNRvo1-G(%YB-1Y= zT{e4}W6@0&jvMDLbSzyw^QPI3MNlX#oqg-B{D1IXR$h+X4MDe4`CE-Vo1hG!KdrSw({7m?ftE6wx zlL*k+1pH+b`_kY?E{5+{AAW>7U(rw|fZkT?oA4vC(EF}@OANhOe&joU z|99{sH&Wp5!;h%B;79)9O2&_5e*A8fA8{TTs*tw$k!46*{Kyid zEq-Jn(iT5bhP1_x%tG4YM`j>x@gvtE{eS$(e-h`Bcr2o?jClAbi$^Hh)}NiJnGQ7p zIz~Dwgo?MQVc5zjL92Z8l8y<-z&SF6JKxmdk(VxY5MQFi-(eQee7TyBbr8m8F^vK5 zb(HP_9}@YE-`F6KJu>6QZ)^|pZvpYA$LC(8r%zq5-}|_>K)pZEmxA2Kqq08MBlA{>_(_@+u?*bc-VlO5P)cn&T|Ix=<{$8 znVhQkucS~-a14ha_b?jf-7yt#*T*Tkrp{Wtpc^A?@a+tWjXI#SLsW*pLgs-FW97l> z9dHccSyG_BJUaw0@#`S%B611JY*3#7&``x8o?yLKRliNLoz18wh`Y)#DHmnSJ-=%x zL3!FAW2be~EZc*cwHj}O%KtsFM63GjE+e{pQM8QabuSX+Spkq`xr64a{fui`aon+cgE973P_APk2z_{xk zB!uUa?li{A$xYRsj*pFTjM?9cYPXp z<euj_2KvGl9(rF!(Nf4I5Bk&7Qb?zIoua!i zQ{q0xB?WTPIatP+JWN~4_QkPs7x}cp-W!IXb+doKl+uFm%#3*9wFNhSLDGA&2|W!oVsl1ASsKzgV}Ix6a#v8;iAS- zY{|Uwy}ei`Cn6ANS72(!Ug<-Qx&o4Ia!Asy1{Av+O{7J7;~<&dV@mv-OcrA-T$+HN zFhm3q9T)opiRtKIhKK+r~ zLw(zF0vQ2-Ja%23XL^&AV#LBt<73Wqw)Mq%f&EUR{ZUQZ@A{HJcprcbb#L~c2%Z5H zxl3IKD-wUNfpFywg=oZ7r)DC}mjz@x`>rcv!d(U~>eH+%YgDP=ODfoXwm`SVv2ibv zIELW$fQ{;}{dDTDv+94jZ~bcyK>cH^`uFy&f9(F&Z}_EOK=FpX&(}Ddd#rEUa8)mF zxDaYf#@2Yp#sTg*C^XVo#v0#>?fAAY^jvSpUFzAEh*CDvOOUihU0*kyW|octI< zesFsIw(u+dHywP~%3W6j@uzwNwr{a_L&uUF<5JbHonDr~tgGpT@PpQ_Ufk0%(c06E`r33 zAE_Hp#<-w8@LNB!ug_1(p9o^S4#T(bCud?&g6%8=pM_0e<+ctWiduL?QqBY$#d?%w zDaUvg!j6I2)9lBjoa|}#cPrm+7rc`!nhD8;9NyKuf_9$mj8~D`Cy1@I8j0uMy7%hp@)DP!MtH7$+yD$FZte( zsy$-(d6)xxjU)Q0F`fFlz*5`m+lj*)$$E(TKtDU|^mAYM8!gp6juZMq`6!km;afJ@ zQGug(UFwJ~&U6=UI4MG$A9?i_h^P^6*J_^@{9(QFc++B@?il~U=d0;GN31g<5lmq->8l@ZpM47 zq4wPg?>n1W;GH+9BWAxKk$1zlhyx-smF@qE<8|yDOy?jy;;OUu%iTB?{D}o%;{#L* z0OTw2YlrohP1ll6avJrkQgBQ5O0)Z^G*x|i7w!?6wx?x99zdnpm7ZYD2=2I=lvn5Q zK{GAUFBacoz0qr-E`zn$J9rZ{oatd0`V0D#(`b|D_lf?<_Iaun(OU|4YaRi7m5Q)l zO7jTjo$v^fX6LE=fs=ceuXDKiF^O1WD)bGqAnA=KexhYQ$nEL%v%7&e99tR+@J9_| zGAiR%i%81LvKwEws`}bVZhHhq?a*&(X0+L&CX!aJck^gVoZ9z3iofmzDlDGm2n_bUFrur(38Y~ zKYE`#nI`_zd_u8rSA>aak5K;h2ouA178BEMn3$;{!2mvhu!SiS)N0 z{<%Sdw(uYkB{h}XBzC%So}P-~j0$f*ufUK%q(N?*eZeraJFo?yYiUSuso-bHi=KAW z7^80)EpL+QTdqv63(|fYP*ks%Jq=`p?dwH$nXxnx8O_hf#1SkRUU=p#C~;Qus4Wnl zJAfRuHOOBpZ)L(*KbF82OkjFYiLUCD{S$(;hV~q>&T>L_gFN9jgWZuZGZ&*_xN@c4 z(Zkd4Xi9t%`1R0CW8Hs(H5e>(j+~fno!A(MC}{eIo$Jnt-mr5Vf*q8tz>C-$c5cJI zZo6SeayiaLF-Hb&*m0Z}d&AD9$Zc-e@y|nWezcu6QQ!AsQ1uk#*w;ykPETt4oaoPc zXv`tb;2N;35@&F6_Tjgwp6Ik$eAgfimxdFX`91+NecX< z979aN!{~iKPFlYJ|G#XHCD~8&Oh>;YJH7hXll?RFXaNye(<82`$h8S})VfHwn=U=3 zCP&l5mv5xgE zz7PENEO?*T`0YD>OMcsEl&az5$0h1?=oo;@P@n@;mg<#ir1!@UCndavzK+%XrBq&` znxPzkuwaMppXuk4{(hHo|81p}MSr!7H{`g6e2Zu?2abq!A!dPxmbBRM@xW%90 z7)Sry;{C{x9zf$3Z_4?U{iuvqAhUi3LA29bLr>O3CocrMDBeRPEB)T2*S?}r#kBu{ z-W%-b^bLrkX^uWsd%##&yH!0Klq9tV-C7TFI-0RJJ6t!LTHn_X{X-*0d3_x9c9Exb zFUPjEk&2prDWRU&w8l4F%_PCmqVf50Eq$rqmeQ&}Ulo%hV*UB*55J5Z$zO3KHStJB zUb?sQl^yT)zWg#%Pl1QjsUvnylB$fw8S z?d7^_{gM4N+VgcTR@agQ>n3x{>OptWs!uKUsuhuj@n}b;U&F&M4IECReO1W)+!`+~ z=fQXni8O0(^V-yHrqkY^er#)x&JFPW*qjKyVX#*z#+XKXD?2*?P}TcHq}3zJlm_t` z{Nh!|L|T^@_92(0?m`TLrO_WMCuU<28ITVtr&iskhI`dFer`blkM>^t8An%A0K)Vl zt@iWPWk0pGKT6uqhdZyW{d{}-H||^e{q1M6-xtA#C02@ITB_5KAhwR3f$Vw(|kJFE5mmk$Th((AuJk z@HMPl+%i{gV+$oJ{Ipg1AsaI~OHnwCTdB3@W)0}9+;voW@Y#)>F9*(ou}fk5FbJP1VC9Ml&dW82zih)93;M*7=i4>=o^mv&KmZ|Mi*dQf&0_$OUL z0>{f*sk_@F?kgQMJYXZ(NsV6QQq;}sSP8Oq*sl$Rg5SC|RZ$9RRZD2r1SH@T?40Mp zbq|c%xHFJ3&y%CmtpR<-BfE`p4>03)eHz7nDtf2=Pj}H?gGuTj&$Ne<(r=L}*i)(1 zBFnxMk(|q(MW+%7&of{aiVDvG`E2AiYLOZ{9X%TF_j!tAP(I~& zMZc(M62d570$W9)N}YoJ+^ep{poNQZB2vEGLURjri;}_jSS;7I_|LkhsoeNd_DAG_ zY0{q_)eL^j8;R&s2NDoxeEk5z0s)k?S!r)9Xpvr@H4VpMzASxWB*4esKykOW1inVw zil^JR3>b~G7PyD0XoCNx%7a1Xk3uc#C)iek-RM&{H15US!HZm?Z@&fo2>9D^#6hh> zj)1=n$xw(dNK!j_DT4VHkW>-cBx-sQEB?Ot6?D07X6FZ zAJxB550Nz++A2hNUWy3M@&w&Dc4OCFfzU84PErB>q6$PTVk%HdzSB{8sLt=+T$1bG zQ3*DtD}17Q3(UD-Joom3BG*#n>VQuT+6ZRfAGU4|VDCU0&eUV+PdK*COR}VlH#gds^oqJCch0rl!9_zm#ZnqWjmM!K&DY z{lG2@H$NHG9-uo`nSyIYjG1FRX(> zkY5VWqH78CdKMriZAChz86Q^spavc~t^aGUAEG22dRFt%E ze+JU~dyZ7_p+9~?^S_jgfCRV?6}LfkQT75qiiIvmnw$ZMP@WD5hD$)6aT!a;(!=Fb zpcpL0PLbET!o$rgFc+5&AdJP-#GjMEr$f>5c&-ax0E&M}`s4K>Ker7EZu{Y=$sm#_4;RfdLeHx>;E@+Lxu79f^C(jm?bt#N7PsOO%Z*}@xV4~N&uh$@2ZoQvM+SNFLa*=?TVD&veJ_epwBC{Qy7qalD zgy&98Q9@N+4UE-o*qMfLJX&xph87CZ0Yv@bsdszJ+7G$W5faxAuX+<=rSyRn0PCLN zxr6@u0C<9)wb|)eboItu*kf5^W6yKS^ajBCV>N1CNR}toX@{s&usV@|46p@Kf%@)d zX57iej*DhnMV+!Umc9N7nup^Cr&I%7j+f zxC4dz2Sq~sPW3V+K5G1@O$hw+Z(kRApI1>CL+eT?91t_qjyVH#SD#Ny|C3((iiR1q ze|4YsGy1mgr@03@hqR2g(mvIvdI#)tK0@zyWoW;zI~Q-|itfpU9~k6iZ9v{nz{{~4 z{evOp_=O%Q8fp^oA9)e}<36-zpM({<^^^oVW&3*mb^G+US4U_PXm9NBj<)G_rhr!7t!gJFHE4&`}(heh*2+`h1wgY=wLcIogb^sn}w{#3uiS& zgQ`ky#n@sBvu*w$@UmL29dRm9zO3epa-w^2f~Iq0n_g^ddVO5eoxh4S9c0sYM4Gm{ zqM+$Jb<;To(WWaBH2omzvyHmK)^s6?+I5%_b9!KR7A~t-6av=l)Z>562RxHw8liRLgx}SZ{vq3yA~DL zL3BBCTWVg))ll(>L)L9tt$cb>w7urU?Hv-^p5%(QHw_io+xsJ|hNivyWJ(AKkd7B< zP5caqy~Xda8PK~v@LmZ8Zdv_>GvHqI7eh`=kIqWgqg3>RToc0}zz^ufpK_~+Ih#Y@ zfc|lBAL^goxBlA?Wc>sB)_?SYtpEE@_JPmSzc_&K@${|#D+jXvzijN&{|{d}fc^LP zt^c6|S^r6W>py?L>(}Qw@*x6~pg^_e3T6~!-U$<~3zQ94pD{E9DGlN=Pt;kc({lv} z7C7&OrO}j`=nPyW8CgT1#7P^lupYr7zUQ@D`FPm$?VIu)ts3@8O)v4J_~n;_lSgF3 z^+r2b1n|)LJQ%K+e97pwxB*P0kqKQkCqSK{$vL>g_@=e7wB#=>{UC+u0(>f@{ZCLf z{r0!f+SI50H@_3x{_M2c&zJTuTeC0iPfXbUO>yo21x!v-q9^b*`q5BTjCwSpkJ+n{ z>Q%}U9#@tpFIYSxG}W0GDD8%7^BNF$quOLdGI#aUcmZvrS9vyYfoAJi@xf3IWUxSS zJ3jdo49C!FjR0StS5lrCEX@aNOV>#RQZL2T)1G$2@wZP=#Xn;$`8X)%t5S~26DX?> z_o5Ik_nkt+8~-xqS?Mt7#d=<3C);&Q`d}y$(6d0Ki4ikTFF-ml!1?obVBRy+r#q{}z z%^ZVJ2l!zh=I?NC;Xn7`G4^ghpD{#MN2j~im< zujO&u{Jlah&pv;nP{NwO@koDe^GBtZmIwR#tBbyD8tq2Z2VDit0U+U3XMw^aVJE;J zKd;BrFJmqEvIQD_v=`dS80ZaON9#sq62Ig-V1sG#baRPQdT>{JpabQNZSLvN#s z%mM2y;v4!qP@Pv51IXaJTKqflh>{MNicQK2*d$)kCE(LahvB~EE!uZ$0{V~pAdoeL zyN9LHP>5BQ1Xs)3Nrz$J1vjAwO}JK%wSyK&0dFwGN9dVyK|C}EI1Ku7Q}dhKteO#d zD8#xD!xw+&1hOyF6)@Ve)Py+sy%lcr5`I+jQa^6*Fi#*rIV3>xjnpTS(7os_b%7Es zM5F8<8}jy+D!jTDuK-TM1awQ2nU|jfnjQqr)U;@j%e)^FO*upOGQF&!KaA||LY~u;nN^RvJfnN3D*Chux63!z7SiS`!HTtCz*yA>+KQg^zili@u zsEx_ve17{muEDkX_7W@Dh!^SlKmX;&K#i2WYv4JN%4>B@>ZV;z+X=ic-=OthZQo9**S{MFQ|v4NMxTGnGj zJYw~o!lyk5Lrt^iO@=gqDzoy&a+kXMTSC7AekTTICfK)?4~~jqxJwAWlOaB-^**j$ z2a>cl^A}Azf+3~?pG0=nQ+EQnY4#T3O z2!^xKHAk)I&G<8?yqX2`@&g!yI4}K@)fB5D`dP#CB|AJ_dVL^X+4_dV(}L%vFiC+P zXI9`^OlMZbVEoOlpa&7-Yil4=ouxs*_rJq?0DZ_elLKAua5gZ%0{l|IuYkscIe$?e zFlQY<+`tXP_exlx`@g2IkL_TaRM z$z5WE@}N?eoD+TqHt&rY@v}Be&)Oa^ZU=7GqVpG@((^g^c^kc(WzFYSFR-!URKOu_ zi3B`0q6ZUai+_!Qv8I4?VccPiyd2-Q4EF<#@9!G44Yritp)15gi{{@U7#?B<7z75f2B!?<v0q8`uevNkXA@MEe~piT3v)8C=c3 zxNo>lJq7mDeD^|7;%?NAIj)Y(@fqM28+rx z(OwezvB0y|?K=|V!-}qT))c=A?TxH7IJwA+miQOXL|$OieRW$;rmWE#toB;%q>t5F zTqB5GBRM*<-J6SBwtbL2Xq&I&LWs>-r8U7~X?6^bv}(N>7^W+ za3|4}n;Hhbj;w7Ra1Tn_Rn#>Mj$dPRX9%79NjPiZ=n$d4pc(?V_%EHmL{9WG)9v4u zsGof%a-TcS`CIu04-LpHrkFxshub#NySRJ*jS3oZBhRB+jT&{kQ;R6j;HBp^DNhy4+?>E(Q+{}brt zfu+8EYXd!A*~P`6C5UA9Z<>Fs^Cn)^1JyFM9^m}otpqm`r@DKG%%R<|_%ZAaDOo;g ze|Mz)*z@!Be-(j6!OlX3N995AfWITW9N6L;n^B4D>zuWP+2Q%&a-<+jfDi3aWiV*g zc;1yaI?xtPoHYeSM<5hJqcrvnvN%xd-uet>;}C zB6|!3JUX2r_654_O?vQGw9{DdC)5jFws;_Rpx3~N0iY+f`|JJp$M*d<-`anxRy7=r zai!RN^^9CCJ>p%d#TM6#Z8f9Z87khS%E(IL_mB5Rwo0g@M2QRsg749@2={9gJKay^ zPW10^S9A3?d!E21V7>KyczoqhK>i8eo{SpL6ZjwuWqTOv>S&()$`jn1uYZCyhl*RE zZK5SasX9nL@Fg9+tLFMA!nm=~DlkQz0PThLGEG>}|ER6tA!HLe{|SJgA1xrNx$F-b z+N8F9kNH}0?nGxI({CH#Ho7fETJ?Rnyb>FY?!?rInRu?iIXtUVz7J1!`{lL}dzOG?NSIF?o} zUc6{Yg=6uerT^=BW0D2EK0mgvPouAcJ|ae8XZf?m3$J>8Zl;k*?lLaMl;i(X%kv{E z@K$W1xXFf?0imh4lG6)`DSRieWTYi6wMk%%%QAsaYgIQi{@AnucyP^i{1Jr0xz=_q z61i~W?ppN_=rnc(rCz8b#cdIndx@0ma&OKah{L`(l~f1GEHpI(@+K(9Ud$(G#ai_i z6$A$7YCSC)i)Q@>SoGEJCc~l{C>|sFx_h6nu!uM`A0;guT7&djG(*0i4r$6%TtxRF zeN*KU;Lweq8~zBrf7znATf4D}8ZJg(`Vd_?@+O;KSWGZ3l3Ha9dtkY1i^f8p;1ssV zxi-{+6fg17sof?Ol&`pqE*RoRTo4>w&2NFydXfS~7Og}bN=2zh8Jg_-a6%>g8}*}* ztO=Eu=mTcAFTM=Tyc}t!Ez(RYD`hkMD9!L2nn6WEdQ|6d5HzdW+=;#qFL3+6gWg)N zOiM*A{!J)Zct2aJM@kQ9i%A9LtF*+A(h|R+B|rl@O|%BQRN-+g{`WH z>ya-fyJT9#iFH@A2`KhO)Ru z7+QF1XcMkIMsWMmP4vJhuIK$fVywymy;Fvj=vKd;6X6J61(5`43pi^%uWIVl^LtRI zKR!b01Qtx+hxX4^BuQN0U=Kf{U;|Zkjzi8zGIzXtwCGwFvVa^7FM<{S_N44v7oD>aP9;n!x(U7dB=C zgX<+W73E6vD@W*jTs?g_h%wlC!9j!%v(=Cf=Xkt}0Sfrzf5nZiEQ8d8;L@}2>)2VddzzvQm|u^x>sbvWb?07$7j zMA0jXxviqAt2k6E=4AJ53112l=36$*QBerq{u!&$oiKb$@dw2M&VnR$PG~xKG;rbw zIZ}Qcm|INaL7I2+nfmjsE>#?-TS7(PjY`|a4$eM3wm?`T+qBmB=K%&5FQkXC3x>>E zd9P{B;@3bs7D0STtQNTgO38>?q#EK0$&STOFGE?27y1FxmQHys(!>$+MUNnT>&zvN zS#xim`=7&2rzSs|zT9W0FH!H0H0}eFrPiP6awp1W8V@fI+#(R8VI;L6sYWS+RM zx_^!K{!vq?wKYu*+&_)$OpG?z}2^DQ{m@(T!W@yA)#%+T*}oMi}3gvFgo zp(H^4$EO;TeWbzP2d`iO#EcN%N-;(ncHEhV7 zuYkg!$Hag+4~_|p|*y9&LL z-mzj#>&5B!&fcF;RZMsEu6qW$(&FhM@Ms~#IW%y3J-(_Q=hD&hJUuQD)ta?u-RKaO zt9R&dfhzAweHO|X2H}-VE7l`RI6M68=tg@-A3~mVupo+YDf?Rmc%|y^x@do!BK*WhocDn>o4;rj}9UGx`ZoFvGcM^YEiNeTQa<{DbI?8|&TUv&G|5P>5v zCta3_x0N`CDxzf%<_3Een4IrI`A#q6OlnoFDkS%5lqK*+%uij>f+oTh6_dI-tOj1t z6A>p*t31|v6d~`6)B~^-9iI`OB>W6ox377y;>%}-TjoXOMX5X z3wM+=z5F2zdk^M>RsV`Kaj%VY-K$38J5Jw#bEPW~8AEce;v|H0tvCqP6oJRA9Dwqta{(#|F9S~}ovK)98ZKqS-Cn#$$!JjSpP(@5LAs59 z!5W`wd|^!E;hI`cShH4*Z-KSS1*x}*acAC1ev0z~ayW)1vDaAfbX!rN4SlB$X(!VE zPPuJg@#ov%D{c7GDFRJG{P`6=0m6Zl@RhcO919sQZd`cu-M z-%#l8i$7zMhCiEF(nf!ZP{6{UsYw6Z z@uxq2RCcX=xIbY(b#E>l3nGswL}N!kZ|CE7z#ODU*x%mGZ$j@nKzOlVhN?OmXbUpi zrRImW(wIcQUw$H9Vk^`H3~fHwjl`4QQTcnynE@vzSiFGv5f23 zUEtY`SV_e_1;wiJpwW%tgTn*Fh9RA0v)B$!O1rb^^mnk;-=`o&*!sI(9uGu+D<4P~ zxVpda7a!PU)3>!-(B5Ug9H)Fb54Z#i*W!ej zRDT380}`}~ti&*W#eYFb>G0@AFJi9IiIYRw5~kzL| zQ~3yWNqO?Yo`8VBdazp{Q%6Srjj0D>ko6Rq;h5`>;t!wP1Xh4?5Ea<6 z4!4B&JsPbW8{fh1%~J>OnPQ#}ig_AfdlDD4$piM3m;kg{?#+>>?SFP}o-}liw}GtX zwl`pSw^eDL+)sJl@w%U)&oPv7Wn+71ILfb-1%Dg>>T4Q{wC3yT-UD47550knu3lY9 zy2|kaYpw&&N33CMk1#W^F9+%MNZ(vJch+ZNP}cbN!%vNGuVFteAEkbGbAR|Y%HZ2- z*dHSJHsR_6fp7V6>G*Uj&4zFN?H3|{_0X>jg4X;SViglV3Z-gY@VUSG<^0wf)ISfQ zY_-5!RZ3vSg!7rG8%iCxQP1b!?DJ{PV}z<=j$=etlg-s!lgvRJthu~`M`s|vskfl_ zHZ+rB%rH3?)27-W?CWDOZK{cBITq8V@}XD2v6x(_P3{3B+TzbPgw#?h<1EbAAkqZo zgAseWf$_)Q#pMyJ-3u1)8U2bneF;~JIdgF~D&_v1D}KqXC`tZfIM&Keq?aDRAfPgT zM&AMXJVxOm^11L6yReyK8}}`PZ^}tX1dCh&eR0NW-l#D}{R17w=7Ucyg)VdxdJm*> zBPlL(ecc+{0xj?cWrRunrmWpV&-a8EZTsWC&i66sJVfL?Am4BhF&#w)rE>NFT_#CyZ0hzbLeK!S;d~rJB~$z6e|DqDhqt~>V;ssb!9815- z8EL-}I063Bu8$V7G!xB&R}^NDd4M;=bfro0M(S(Q^@XbT%Fbr-t5WA+846fYS1_kw z2-O?ofx(t;g=rLqRgfuZn3bX7@4(`d1|gRA`=f`_i5gmrc*YAf_ty)Uj>a_#-5pDV zPu2~mCXKRW&_4L9754SA@AivMcmToWMTcY8QP*{Ft`I`Pv=hDeAS#zv&4At-cmNd@ zPEYN`nWciF>?JO-Y!noC+^VCvOg=9f#pND^Crc1D=Hh!$Pc&+ber=(hOL9s*=8;>)&SY$YpD_MP=<4aT{h=M_3 zwYZLw^Rt)n4P3JjW(-+^rL6(@yJD2LL(#0Wb_mJf{y{*jCZ7*C*fuf~@}m_}lM zT2ZkqYPbKtdj7ZC=ii*Ki#uMIe18l>5+ZW)KqnajvoGQ}6ITY`eg~=Q(Jt3RXA-Ro`1N3}=)^A}s-&>*2H3re;>Z+Z%3RP**9)Wh7 z#1PWd$#u;wo+n?$%ub^`I&vk8>65OT&_mlsz7^=9xA5w{pyXeHsvz+eKDV5dd>Cj6 z=*1#b!ufY;UzAlSYSHoaNH?Jy)Mu_kn)-yB7A^d@95&MUGPv2czcyk3q8-=Xa)sz+ z9|gIMsbYvyVG@3Zbz*E3mVz@>yh>dNdSOr~58rC{4#n~$oIuUG>mt3=U)L^)E4kp03B>_DF(_}&E6c8uh9C@++ZAIPPb(M$&!AJ z*Zl(Ji#W!F=t!o12rEgSKGgvPA^p7_(tP-a1f`2udTyf9S4(O6{%w@z5?ZfZ*f!9* zQnyWK_gDC;R^SAIo^&Dx-J8)@@gS)<8;h`X1r{<*JotBvg{Y58zr7U0^T$M2P6$wz*g`U zf#Tgk&+YF$6N-iPR1My=;}8cQZ;0!!|xAeMmJ(>{gY zon_<5e|SfPjsq%=smM>-O+Dxgr035)uv!a&|87(+@Q*p36A%B3Vf~4Ne~YIBMID4W zphG6tf=k(oZ?1{L@X2X57-k8)54Yfr6$+5bS#v@y;M|y@LA5Lkpt=qlt_@VT-b7Hb zzu5AYlQWbpPv3*N0tGq@tX3g?AYi5Us~PtFszPIHNoZ>!8f!QMok?rI$|4uT(-yFe z(17?f$#6Z zYmibeJnhv&kkQJFgY*ef5g^EJtV$9jbu`3L&t?she= zY8jq2LhT#?gc@{9G75e4OybrG%r0;%?`s;jESqpU%C-V5R5mE2;Y62;wEbJY%X+5% zQ#h)s7=>?Czp@P5InUcw%*Lw4Njo?*M$gxMb1H_;M}4^N9{s45_2n*oacPPA)|ZGg zPII{_<=PPd4`-M$zMMM7mou=MZ$++UrvTWNuWG>dE2Sp~os6$dk1tdeb3M7{3LpK3 z8QKJlA>bd2=7S;rEm6;clZIgB+sa1?OE!v$K3(Qp=`!0vmvi@_%hJC_lmqE#)InBHEX6d9|^tSUjD&b`1TKd?jC~V2`Gmt*e`q)&9K+pfM7Mr}D zYv#XdZNpHYSUk7hXYvQpq-2}?F`xm45h>3q8y}tYWAGv1-z}5QzX3V!rYF54I_dwa zjG1&F1S|Vgt%6#>nyM8{o2l9jQ;3l*TO#zW%`iH+lidEbc;D>5llyS9e<^=L@&r;*hl+(-T#o#;5aXZs zszbqi%1M`s{E%eV`7$NniP3z2g=nBpaO2E#&=DSAE44OuWYaw)pNlDc8HQ?v!=P2+j0{kHln@L}t(j5ZJ?e1WGYSdu0G#NKu`~V?{yMec4R-RA#p({Kq)R z38BtU0S8(T{Ke!!qnR1-=i`Ch8icNo#Jiq@mJaBw;=xb(WLgX{8xcbiq1CKnO3)nr zLFr{TU`pXHw0(*ySZ+acK<7EArylZ6E zpywN;@OHmra^ z4yIZ|Dl`1m0}7^)pr5xKmoYcV`kpz4n!gCfeh)1JV>>VX81rm2?8MAlK)M(ziqR$8 z)J^)yYy!Ur;WJwI3!tC1Z3347|Me!Y_i$_iyKhXk3H)OUHvu9An5z%w>rDU=TEE~p z7>Jvl8{G#MBE1$!I2`ZiB7G;)DCW2sX_7joXCqA_!8|jNCel(*e;v|9ZRVMVblL1> zj@xG6sKZds$DJ2CDCPg3LTD1&84DEz5CK@~+!) z{77TW|4hu8gZo;U$NgNfE30)*0B)rG2tQqh(HA-Dvb^5yfP;T-tVCOh=d=YJ=`Xzs zMc)~79cP4HGWuqo|1i;mLkO=90b9(mKc7glqtGLGrNDfEt2ALNfeH?W*;kcL`Z|mb zbNn#Sk~P@uY&y)JUO@t4JR9pNXn>2f^h}dbpxe*@FVaiP=FZt4Rg;XDig6iltbc;& zBo<&Frz&VUA~-q^UUEo1BLRoc4vzwZfr+a)jPTEWr4e#wU^R`IVFbIum835=@l8m~ zn|+)Y{tV$KJ(NQKAYbmX^Ruf!^Vr+1*+WT%=`!qVlbSR(!tQd@aKYKps2R>cr(s7n@#`4;-d#N$ec>76#*C3PCe$Nc z;BnoG;8BRqS=5UVo|V981>>}!1V6g({tJ2&$#7jHq6BKt5!i5EI3!Z$X-dWeZ39?CS5|5Ll#qnHfZ-WCki_SfYQ(@6kYH>g zH?1zSs&#?q6aG(!$Sg+H2)3E!*?>{;(rJb6366(C)B>w}&rHy_rEqI7-(9F63yenpF3?sj{4CQDe;U2mg=?!N6+=ul1nYhOKe^H<~y&lH4+T`v1S`YU^ zU@EHskI$J>$AVOv^`HZOH>nS!(zvxAjI!xi%xV03ILTTMnLwBAaL|fb5lqSf`(*j<_{ZPB|ogOkW-zWKz2HZ=HtJB+S{qLy zZLN(BNdIqJ8)QUeKYPU5A!uA^I1j^&-yzHvexFE81J*xwqXRT_ZrKK8h2~I;6qI)lKDHKB1ct7|Uq~R1FTHT$cbWDE2lGRTYAblR z*OrH}Gj~QULAUr%M;c9wOik+o+v0a@K6`ar8=<=hnlj8C6yYZz7ia3D5hDk%si0h~ zdCXw8u1zuld86~_R)bPXw~gM4C05_SX&G;H$7R8;GOA!CY=3#?=GYXIoiYTM4GT-dO6aS^Bv%oDsDf(Ch~sy-&7w3UyZ+W zoV&ADjsI;K`H>zB0VLXq5aG9;Oz5g*lZc!+UL)8b&d&&!30qH#W5&VPG9WP-68*yA z1+g;4o@Pe(66`5v^a2Cq%2S&`%+2>tz>vj`ekZgg>5V=%{zF20+g3E+ z?D+_BjNnPI7^w{Rvk<9zMlC;5C&t}*s3g=VY+5xL;mP{-OzZm`>-#nO`|0}oMC<#P ztncUP?>Nrq`3Qml{8&E1wGAKHZA%}5S>wo(!#l0{t~_kfiTKQLmbad62tsTJZ>+KrEy!Ce`f!8B>~gMVS7v7{NHn;||Ti zh8gm_PgKtev6y@FkSXe6hy^uL7V2SE0adVn1*$ejp>U~=Gix=o*JjpC8r+T>Z5$Q3 z+H)?qM7;_=8CZ(#Co^0el$PijDv7whY=9+5_XQV|9^bboLn1xtyakId(w$0|9$QA| zI)JYKHi{x`xI+{RL!NNlc%OjGv>)Sr6KqPF5%0w`+a;xAAP-zM8*cNBq;9inE zgD88I8=cj64$(r-duR&cInYxNG zKHYT1$Vj_VGN!2zo5F=_Z0a5~rKec$rH|xeFFhA31)GM!dja=St}4*Pt64zoR2ZIP z9kRa<LW1xeb#F=rqNQy2ZcC+ zshAVY_09=Q?L(pt1`V{9>=jAKhw0BDk^X>0!EG7DGPXAhBE6CD9}z^4(x}Ii(W4eUumi;4CuU!>OsEW=2p$b8ew-Krzj#9E^uw#|`mj$GFZ=F!(1Tez zuY*pD>VU-yVy*hesiFtUpm+ghcX-)+oaUgD(ONZbB8txV`wV$_@+5Q{9D)iK4KFDl z04*oh+S3E4UIu;?KDfw!D|Dn_sc^(#Snm#O*uRA|gvY?dJnEZvf^co`fLVhNmrGXk zfZ1W=P~PBWIb!4ZE(-A=l6+F%5?$<0t-X?NJP4u0rbew5?Ey1rreMn`thM96luThX z>Rc|nQ6R+N56)%(goo$e--MEuzUU34E&F9V(hFxUn2jKk^FL1(K=7+c<5&FoO0i%3 z7%EM~3=j!uDB=d-XxF$q(>`T6?n)Vaa@$wG_ z?#*p*f6m^R5iY}I;*0NtGb(WCNGC^D4wvHEAsp@!^zFle0w+B!U}Q1b&P*p;iQ10o zN0WAE&#!K~G{FZpEKi=m`%Ti9K_&qXIneXfl;NKf?qxKm3ty z8Hd^zpcGBBThe|?dbS>t5saLShZut5!!Dv;(|=nj@v9hBYy8TqI7Q>v;ELniPn9}- z9}cVl#u4=np&t&_QbYl|^fOHsyYIQ)mdR<4JwneLQBxv)$deF|*a5FP2kphp{SCUI z{>iuAFOt9e5SX8KiztMus&W+bVH{- zzTYP>s!%!*@B77Z3VT@g@z-@TxC^*Afo50zPnI2cj@O9f^sz^IU8Yj=~sb?C4S46*v}5OCGwyY01W& z9Yo}I6tH+Mh4hlyi)YW=AH%dAe*MkoE3jK?9QT}!6mMk_dU~c_d83x^JJFv6!0551 zM!A&q;SAG1U(fW4QJOx?Tz-hA54Ya|LP7d4k#D#)eTDJq(jye#hIJy{UPi}Z$HzEy z)cV{iFd#c|;sy9)`XIJUP6qS%0&c&Hn|)F5t-p`Iq}G zzlk~!w4uP0TLtr(Gt1M1t1iW6-Q|8Zv!E3bx;?nl9uEM=g_SHPhz(7)2{X!z2c$eA ze?)Sg#v}h-I9-M__u_Dh$Ph3;?hKFcRdw|8LNuJs!}`GMosvL!fSpj7hv{c>S?3KH zpsDq!m|C$HTg|?%GthwHLUv+3NjcL5Os%A3YcXqNFBmM&P?|?6qLZ{Asg(2ksBng2 zPe@~ajl_L6M$%_~&9@`uTV#G8iq3BVrT{uJ9;F88pe;ru+KB~ixX#-=@kWirQ;c)C zGR3fU=z`3;UvqqU=U1Y040NzpYn$ZPbi?US@{zDheU6hX^VcXtPLdA)aNyyQ<&-ZjU&{^n}06q*GD>IyAnr3(cwwT1s|xEg^7%R*(AS@P!nQgG zbXLk_$C$hpTr6V9en z_{hpdec?7U9&U(V*kv!30CtSRY|oM$ezW_+?~IEM0Q}-fo50iX?+NW$f1?RWdjZOA zaR?JEPf%7)oP*$w*g$)HJp*AqDb>mADnV^rf>H1tga;l7Q1)eFUl|>($oJvkN>ciS z`G860L%14AySR`KVV{dBg<2whn2~20FONE6{f1(XU+Vq$W9S`$Kipl6Uk(^+KZp!i zH68CLASWqhpUVtjx7$iD2ZsdQ9_evz$2RL)k{SMjg&sYo8pKJuAW}{EDSVc3u`l4~ zyx{dd&A2cg=wCjv>t8mY?;M@n9^X)a`s1y2eU1P*F=(>0&7RjCWs^RkDy3dMokK|M zMS1IRNuBxu-ie2fCwGu%nA?8>bP}2@Igz4U#c}`xu^s}R>VT)F#lM)a!GGp9lu(G@ zOVn@vM0v;wvk(>*f>pb#pGU9JJP+7qR9+X9f}?jdti3zK@&0=Od5pXqhzj3-&-dYg zCAjvNE%+J-Cd{H=mX(T)OoMEqs~VHM>CV=AsFQC+_gzGKQ(@V4u*={O7|4-pi}s z$~K;GEl%ah=Z8W2ylUO?(1%Sv2kyz3#yU0qBs@;TBOktXzMel*;O`W^1%hn8rUY#9 z-BYlPtD*j?Q&aGj@9)C<)pwwMe3JRa*LpREU&~LS5l$Tp9hI-?^e}AD5M*-79jc-M zhynKqM2#vPhB;S?n2Pe4wR z968GfTcjfoh3f%A`f1*Qv~^F-GNid|bMU?rX|A|zq?aH~ykq_aNE4t;mmyubaPCd| z&%&iR6zRBa-mIBlb6IlFi?A7N$?=yBF|oI28a-N#FBfR*KN~ z6^1yiJuFJ!wdTD}t-?DyeSb@qB-u_zU`n69|MPe8^!*-`|E%bHs~ORz!Jid<-(^~u z!WIUXDf4(S9!aq(rd!nN8y0P6g0!8#hPLOl8A641{L>TQkc8jo&$GzW@UkA%s%iF| zd=Q|$(ny_p&D9@~{^2zs9Z89FfL{%fzGLq@aYXvpKTANQ{{e&&BK_V^4UwJ&Jo9bk zU*G}tT{7fZ{SR4RF(w3h*sr7Gei{^r+4`k6sf+7*|9 z(%x`-GD^E(I4SL7AU!DUQVdp8+WSa1Yf#jpvrR}_boN=KEjs%Q(iWYqNBaM$Xku!w z>Eokz`bfK(aQD>>+>KHa$3d_$S;W!kbB!f(gIbOSZg^lKJ)@U}p@^|X#eg{odKFyi zQh9u{|4pC=bi#Xqv%vBV>H&!Uweq&}JK&G8xaEErSBW|n?n*&Vn;fE9U6m)}oEqOp!clxQ8jTdYbP*EY&aHq= zS*um{C(*LF>O5x8CT zb&X>=I6kpK1z^R8_1dX^dNk>6+vq>kJo-x@lnqDUfka*F=Sxl4rd&?fhrnr)u(=$(^LYkJT0S7Fkj8c=d}0mK8;~B3Jk?0gUZ(F_g{gY(tm%A8 zyte-v-fH^wPdoi`0k%TF);AoU4*j|urXV7MQr~*_9grQRZV-gni^7Py*Ulepdx9i_ zxI-aNJy1xgN(htW^?X(Bj!JQFWSk-(l}P`80fEwIwCmNS7XpiP6qWT5IB=FS;O_#$ zXrZKDtpzg^!6>Cp#I6{W3>u?0lmMefLkvxfQ5QjAi-bunV*R4C*Jlehv8=(PH;`^O z=|3TD?V-DnmUyW=M>hZV+dfNl((~o{g^eF)d=Z(iO$nnT_EEMx3}cO+uebiD=j$iA zkzI!Cn<90nvt17;^ZuM5m`oeQBCCJx%IIm`F1{hrko1#ovRu;jHWV!BJK) zUAFo0!M!FZne_Zjz6vn@#)--1=X-~9eu$M=@$1naYksgNIi|9#nUh}o_uFavh~Cb?$dESSFPCrz3Z<8$#>VrNpH3(W7zuHCvm*o$KVE{Z>ej(-kj zkcYPC!cyr~d1AsgM?ut?AHRe12YG-)NX~{pmBR-pNx;uy!wKrR_iO|3oYrq|`cgpY z-wcCsTW6r+hJ4f%&*Yf%RioHX3!@NwHy0}S^1P6LJrD#mV3qnOh<`vXVh@Ja;-$I) zN&z5XPKjE9PjDs(g_v1w#Tdn?y{!WgHglS@Gq9y2bp9*e(9jj7z=5lPV>Zvh1w)85 z>?rx)ks4_b`xq}AHORjTJ)e(s9n#Ym%sS`Ou35bv@3XJR(}9;PN&E8uTKK5MD#?t4j5<-MM*vDaX>z7GeG#MF2bdcLx0EMSOU&-4pV{M0_W~3*l0EV-BpGNJ#bx>t(NhP~qu)Xp$Xz;f)t~_^D zp1J4oR`s69lyt#?V2}fQc=(PmEGAZI--jpA{2F~crE&~++~_Mf;`c)6M zNEp+7RXZ8I{PZv`4Ye})KE!37k&KJ~@eUR|rC&%XoeWR{!@JlS2qVm>0%NB+w)Eh; zueoGCTCMr$k$69bI5o&s2ajR_sG1D)qS!eu1F=?1ok4^x8jr4qN2*2m0NBCAKNc@Y zENJ3q8cBx^6xk=J0h`0n2J4~in|)E!j}ANiFxUj@pT_;p;$HU>jW@7^E`xjB!J`{H z?`2=j`80A|YO7P0G0*|t5QwdTo6Q#BVj#Jepi8|1TFDcqIT$A9yQ_ETdVMc&0Vq#E z?%E5=-JXF^HnJF66kN@RDQe6)tQ#6=Tz2rs-gly_pVg_KQ9Poty?a(*Fk$#*!3I(@ zfb0)o$_^|x$o!}D2V4WPW&nh!1HzRW_rS)^cNlRC;;3F0J@)I8do)-^px5DkFI3J% z4!hOx?@;J}x^c>QCh7ea5rwIqX*eFhGdTU_Xi$vRaesEos!3q8gHbsS$#%hPdDJn=yEGjE2 zEc|53N^IzIv(Sd}DXN)MsqS^Akx{P1_ItkG*L|OJpR;qefoOfczv+Xs>%Q*mzW%(g z_w~Ns*ZbeKOU_S}Y*xuV-r?j;+_m^btFX0OZ4|ED;eWTo)%IujyM}VeRHuYeT(u`` ztv$$l6?Ucb5@l83yd+H2s|k_X_mhZEodzcg0xx!zBC)IVrW!Ic2$^~v41UMfD&%AG zVDDaIee{5r3csDhsJA8RjR0WQw=u4ohUf#j$ZQ=fNC)*dLFn!#&3zCvAAtVtu4|eE zI`593H=*Z<2G{+ubl(M;tlO-rBQ;04#E_adyF@|F#ht5ZC>~vxsAw9!B^F&>bFyf> zjUqmC^>oF{Z-U^jwvauF3HciiE~iuOK=1DeM`a4J`_V~fQS5=!qj%Q~16s+b_glSs zuU}8e{dCcb9;itJ1O%A_1Qi5}_CfGH3cG$f5G03rcaY__-n&1_)_Y=k2BS0uXr{tT zo=<;-r-kNUv613UAe_MWXVMRl2B487>AOiwmiPzK>-=;F=}V`~L)&uc1&iiJEb0t!m+@t!1a;;xdq&r#Y-{!>#p2B5m7t5lWunLnhLZf!KPvCs3lAG@iifGCJR zHBR5ZdeK$ljsWL}DybReSJLYG^+77JMbhaAdgmi_rt=~79}5d@EysJ6*0r)!*OaRA zcK<%zwVD!dG=(~4#nQPv_?YEJR2i;1#c$Mx+`&RC?Rs9So_pt`8LM zPf4DgIneLGHX5NmbK;g7JYb<;A9gj8+c5b|e!YpFSdb!J-RZ6W$BT{*`}@rTeQ)@^ zKX7AT>M(rr?SZrGFVm#lagKjQ>gdOpf`$P~m}ivSh`zWTkWJ{&{iju{@eH zLaGxpCjSd*^03ZxD4T3T^RDQ`$no4BFNQ}D0gS$yC}b#8bsSSlAc?;=#4&7?aQ*t z`;D!)Y2c!r$ZHr`<8cfvkG$emNT0vtAUxqS+t{NG6_i_=KC`{Wa@&<#md-7-+&28R z2tU~pm6#COcXT9}!@=S{W_2e1V8j4Aq!msemQYT7t$t%OH?&08(?2w~(GipqZU2H_OP@9O zcyo}(kB+vp$x|9D7*O`==q0b3g-XcRQMP$IcG;ni?;HP(PNl+qx3h0YSn6@vE;9{5xAPBcwN<3Ha?f=G5z!_Gz?sqfS0? z1^i51%QemAjJ8iIeItOGMF~9N6N!r%p!d#G#K}iU#uNIr(6L8ya`4}Olw*8ng1VD8 zWYzw5f*poCQTNXiYR}=AI3y!?dgfDjNdGEO)3X?E-Ddr2S9wRWG+gB5=ipwf5p4pN z=p0H(g{nOgwTiL)CG{J@NA?x&g^etD=YmlQgQT5fy)RlLf~m8a=wVA-PH|VO1B}H~ zOQ;OTr^J-=hXR}l0!}evy)58t@cw~J$$vi?i9lBOS}X#V=8u>|mbRWxvrcdD3J`0Z zZrLSuzqT3E8%|pryw4Xh9=SY@!4%huSoTt~$2~SbR@8Y{X8E~6`M1{`6)Hb1$UdR= zdN&)X7Ea++a6@0Zfuqy8en>C%=6B;IOTUP{(M85`W`RAmZ+A^OR7%VkG9 zCpoNBl8`jC4`)Hq5pH(d;9Ua;>Hy}jI1|Tj;mAscb)JP-SZm(!G*;xIt#b;XUm_E#>JOZ- zox*5?_Z!lI6dA<-Igcx?up`||uZDEbc~d?S^2dNVR~LixQ1Kh+fT(y`WHpz4Mpp1? z8=x9a`bp9o{Pg3bMcbACC~1LHwEbbyLMNr0NMC6j(Y$MFuB^E+a^37jvz^y-UjAe7 z#cP9r+pj(!-mko1zuF4+G@j4I^t)f(4eO9)V&gMb{sy()I}Fj7FWD52JgvZX0YJ)M;_?inGd+V#_-6!{= z)X}f4vuBpzj3e8ZtBGeB?-zjI1<3G*rmy{u$WY<81M}D*wRQJk*O{@z}Y; zD5*0j0qoU~=+G=YfQ-eTh1z#A3#3E!eIc{HPpQ5J>dP@*Q|O*|D7vOz)AcW;3yFli zKbH#3+Qz2q1WX-*>8hdeW?XMWjsI6>;|Hm6nU{xpe+NWTowj``l>aQ?4@Ol%f%MKG zhZQ%-XNEY$0iik(X(q#P{4$!-5F9_lqsb+c3v-NoghqZ8sMl-cg*I|~KaDEVhbB9IMxMlp_D@ zy{&u_w@jb>FNXZjEyzdy7a>RDcnh>4|4T5SbL4-%**>n|ThV{f^H$R9NsHz;k=D{t z`p2ZT!j!&`v`_6ZC%8Ov)x6o4UwO?H|L4!euZ=42``30J*D|yd#{{6<_-??QO~HNp zfnCxM`BE;qc4(RSa+ZtXR6#&F6CP%iGG0;Uwf_y#<2R@;ENU4gji-~3yt}FMDcXi& z4i7lzirtP#&H;CEsz=_^QyVV-b;?s4r)9VzhxSI?>4v%S+g@{*x-p}7 zH_E-q)(v|f;~<~vhIYcvCI=-bO}ZO8Ro$I}p6_9|iGFRW>z-Kqfs6{QGnu>It?J3o zv^8b|q}+QzhG8x|au28KOf&((nRn;7n+^D0c$N!(SH6*W+D#WmTfbjb+%vW#t9k@;C zfqZoj)k#HXK|P^DEQ>a;0xRS69YK$JQ;rID4{LX~6x7}C!RpX_MzF!oqHXhFT=lYi3+2^Mx+jE_t z?uWJXH*nbCn73s$mCX^_yTJ;|cxRxoRedAzy%Z zCnx?iyZT3VzJO7$9betra~V7Y=dE9a^M_aO2=X5Y<(I5jid}j59M<*Q-si9#E^laB z5T<>;jpfRb<%dWU9iLo#1tWHu@8ghU8*lSy%SvzNCWQMGDw)gyx?|SI&=dJ`xJEQO zu*$svcrMMUnQD*mSO@;_Q*EGjQD1HNm~aC%gpLW-Ja&E>%%IlnPMLJ*B`GyBpze-s z?SE9KtjNf4rx-MT)j1E3H4yIf;c-4s{^9ZGLxRJj=2fIc!h5B)MpxQwb9fAa_de#@ zAld5(zKgHCvwC%!6Vr*-V|%{{dz0#2!PGy9Wki4~8AsC(P%H$iGkNTsL-*Xo){J#$ zp56!R!!y4t)ORQHU3CNx62rpt!c88QI!Kiz;bW!gOdmLp4V5fev4wZca}dKng>L7< zFo(dimKn)4`8R=pp#d%AvGcR8%F$V(jIDy>-(cD@Cm%RIhuS}pu=giYL3+s@+z~n( zzeRpO{%r-(w$upU4Lzg>*tnW3qZ2($s6)Tuv2((nJ`agabS!j8{1%_Y>y_ztwDrrO z$M5AlkeeP?(D~)fQ$cu`nG4_;wWF0r?2LFfp9W{dF4DmnaVP2EjQ9-c;EcF~^xzqB zU%0*3{*CdA;zEogXbO8kI4g>K*vU&SYqtK?m^?+PlPUvhGE`}M;* zf8t)dy7aQ?O|z{V+mk;|62irOICd!tOqV?U1TX+*aUx+a6#5+Q0pv}rzqL3!<}UuyMoUIIfE)U z4VWMYJG7#wqr1)WQFFr5>PB~@rB%F7r-3&BKN7GUdy5|yrZX3QC@QDJ4;2aUBOR+V zj2|k|7k=m~Af2AR06+Ahj~`0*fgijMW^zB`N2t~e{7{GY8b5YOKlbm&5BU}u{kSiu z$D1#Vnk!9`FO2dHvJwi(ivgCC`+I->HanKgGO=K*JrH5j%dA`WKmI+%zZTgW704=t z1r?YA)gyEHsnG=Ggk>(3-mz96L1L+|q+T1e6PLWJ_9&nAcoVfoI_q6CLy{kJ@8{Ki zi1$yyei7NRC6cVBeYI_(&-;#sS=bP5 zNfN9t5XihULm<=QcH#0EyYMCs+OyK;M^8SjtyeIIKI}li#r!|QQ)Gk+Q;TG?V@O{+ zfBqXzHEcf_AK=5P#$)J9_VLKahYMim0{H_IDhCh$roaM|+IfMoke~a4iL%NhqsxOFh0`}nZ+89Ahu8}yV;9?8>CJ#pR7`eadEYftAk zI!(#zQcTgoBSRdI0S3fSWiLM`V2w!B%B210#``bAJiID57l z%1g&9oVu0tysNK6ar@f$m3^(j@M}_lU$-`n$d6xteRDqi`Z~H9-JS>5$r#PYuY~2M z@k^jf<5v^F%)~F{#MkOK8^2njYv>kXHu^@hhbiNu8FCZ}26cM0InBnj$s9xs(+r1d z7Gz`E8pE`sgHjE3%NimzXBmcoXP{Su;aNip&+HZ*cqHK$axodBVWLJxgJocyhSk9h zKp=!y8mjP0fAt^71yT;LniJqv2||PrUcK|z!YfS{cy+Qoo6>l-mGS{z?I8W{#;X7y z_kw>jEH{l`n(s7zX|ZPFmvZ)ve*NCn+%Nt54HP&{ze-lD zG7QY5VP3E~-xCxL$k=QS(Cmn2C@H<8>MBi@6rf*>38kvT8CjU|sg^ZCj+>9Wbwy|({-5hRow)|k}Zr~>Bn&Uk0BNnRPu(GHF)fC_@2`r&77P!Nx_7N`P4E3#41tIHF0YB;tDwlHw~fb z*yJ*Pynn!Pu8CusrmI96&TY$fLi>IGp?T-@pfRPoW3>KkMltfs=VuVnC#v9plVoYwXP3& z{L%1$_<2H!-x9BN1SaPc4jB6_Q9yD=n<@ zuB8jszCNS_(M|M1)jT!kquOg}10~OOdw>=g?UFPBBLb{d!}62Ts>_D8qg$<4<^X zEZ{_Y^1VrP$2H)+$C45adnc0gML&12rETVD9@^4=^>b}$8ZLP8 zG%6UurAYoY;xk6@MX;xhA$=wGb{WX9A07xqmY#p7zjy(1=I^73VxZU1UMNud?gl>K zq~4A5*BMkJnSfl;e3`(FFnI*-$dVMywcJ*&!k8Fstwrgu-2#cox}Hj^PWpa`|L)}P%rltkMn_v? z(FfJB?sRv5#;(ncAQtERK{g%SEs!L^G~uK&q-SE=;wU>t811C+qY1%de*BQ)E5Hx`O!Z+{&JcbC=YPx1haZ2mMv6QC3S={8iRC_8_ta&-WflSOCh;8pno!-ZVpFOL4GqD&u386+l*>uYT1FFvL1obzocm`}W7 z*SN>MS7Dr%H`h3NSwQ{5etgO?u!wZ?=_YzSoOIdO)A5E&N!MI`UF6bh=Dn^l6Ej!D z{(W-mtMc)Xed0c>uOjGW3Uh9Uc7)cK3yr?X``8cD>njMCehGQP)?VvthO48m_4QF< zdgl6?i;y9N0yB8@*VpXS`dXK9KteB;$MfNhJEWF50OjVJ+$cjUY>^I+c zJqs4uNvJdf`_N6^vF^!VXlrS~UuggQO^${3s`E6Xc3b@~@)%xdv%bkftB3E*z0lS) zg%;YEsNXF#t+UJcGFWFzNw1*=t+^$n|F5ny<9~A7w>$p$aTs&vT$l2qMI9@s@}DH1 zN;7(*wkbud9vu}cxE-skf+ecvT=_wfcV*EKav9W<>yLPZ+ZFG2e(#v zjhh8%LKID4Zd7GLiP%)m6h(DQik)=jtp*g6A?o^L zWlUP=Aq)@XYr7jU01o&glfRhYV-`9exK%03IRn1Tl!m9F(Dfy!z=itZ#~uyu7xxAH zm=5cWXQkUqIdJsi#}snG_groBWCxtrx+Jfw zcfEKS(R3kKhwQ49`egh;W1vXU#wdBrECGW z+K{pc4Hv#*TOBtM={s)|=WMr&s7deJ?lF?EIB4FNc3nsL9^jR^zUe?m*=gF zJX70Tn|HO2?DoR&J9(qezOMHseA5~!RN%Jt{!K?zI2M5t2WHj%?cIRLJ86T^L4ncN zdnfe>Xe8Ef$gcFxXAh0l%Wj?C!Y6Z+cuQ!LZS($2vA7jTmV`RBgKQ^9soubTQ2Vod z`@xDIX+LOkjMqwr>S&ergX{QGcC6Y1R*??uSQ|*sx%O&Z)qQErqT2oDs}Wj8uUpdA zX9oj99?AObXe=Tf$VXEPW=|>@;`i8^VJQ@>(2vYEA0C$Hx-G;It9=`G1VbbNaWMxE zV-^t}a6}`JNAu}lpes%@lc<+GAb*MCpk_SgiYY$KbHSZMHQf5aRCmgbvf5g#D zMf%&tK?1+%w<+%6P73Z;U|BZDCHcktok0fa$akO%x&%_A&5YRB;!h*XCRYy=Mp#* zS;H4Q!4ZLRJ?Tr&C5SH0PFL1kdF?fCfVjiva~F-f`OFBQn=82G?_d`b6~*2sA!xDa zPK$lzCTOexRlg;eplnEwO+k7dCmXnh6r>LaUV`*F2@9;n;w|<*^-J=K;*|&$cE_ep zid9Zg?H;r$&oms(=_)l1r5l-shab(DhIVM;@@9>cX?PCyPSY^LJ=ykw^TZx#h?;mPYPP+$GBH9 z&98ux#L%T=RlKsi=Sh%xDB}yO0ABiq8}D8)CO!qR{-->?cI5P!^X>5-LDA#e6NKgC z$KNeX@f6gK&29Hn9eDY|YDwdJ3^NAX7oX|H3qO0XtT&3{RSemS6|PLCUbesdB$Iwz z*>b&}Y_H22+Kw;;M`#4WZZ@Sla_Ipl3rYW<^0!j zCt08Kd#^M<3{jjILQ)c?v8ltu6Z7Fz|MF05>W5!B=84ex_NstinJRu|Gz0Bdel&`X zq?KsicWp*w!c|)?${C8N)(V@kjVUUFo_=xk!`qMrm+4?ugVx;<*o4JP^X9M#$Lbr{ zSmSH;i+aPW+cMmn_5%onE3yXp2@)kR)80IPFHFIDx|^uD%RAle!aTtVY3IJn`^p1? zR?vtfMBb~YZZaAnva9!}|4|F}{@s2H%3eYBiRfL>Xk)5Aw}#qWav^NFMO^a9bs7@C z`;I{(weR2MtyLyFjV%F_*;UJKZ?@ZCJZ)~-#gwu}3Ewt8YM`<@2Z)HLc4O1t8 zwk7vZoq#d&6)n-*^;VqB?R3#)(J)DbHHimu$Cwt`4uCa)13STi19bBkOnZBw+>9DDz!M&TLJf&-YeVlrqykL1Tub zp%eB9CzM_-OiCyPyI>Ri00b(uEVh1+W$_t0qBZb#XqkVO2$n?y#aBj48&XuW??$u~ zX8J8CeKpmGmc`AVO)ZNVn9c;tA`X&=R>8-&rMTY*K&2agk`I+W$=N5RP+TRJ$=M9qls;~_Q7 zP5PrZVZrVcR=6;CC%>9JKK*vO_vno>Aj5G(hGC&%zg5pFx+fNW9P4+bVnrK=Bny*6 z-`!+D(7>3GM_?WIbwaYH(9xgGVfrH>yd)s&tZT31qg(MEK3eQQ}=1Nk!tf;4C z#a#$RU?kG zG2niSjr%S9DHQc0HZEYKPS)3uR&Yf9O=TE0F7iGIt9-h>DXIISKZXmeTFVTE@yLo` z7^mu`w-{RIhA}5KjJ2vi7|G{S9}KhF7|FZRBT1-eFqkVS%3z*`2q6s38q8_U3}!N= zJHNtIAV48$Q^0tXw(%(89&IkZZR2S2;?xK$;obxz`A40#cCA_qvo%jVVrB4a`R(@zgL*)b?-oJz6HOwhOD|fp3?N8Fh zq%}$UYlBk4|LEI%bh^DMsS_V1l>MG)ng*wGLHonieyjI6-enB#FAv+`K9X7b#ZUAa z+;3eLb^QJg4K7^yPk5IxxbKnS2FF;=rW>IxbfWMabD-wfH^iz29Yon^*;`}ZSdroh zio9yLY42~};9YaM8tl7= z|Ky^`9rTQXky6sDNNZy&CM|yM+JzEB{oms0vPkS3`WW8-a>}Qt$v$wC^g`P6OXHQC zq;SiPNt96(-ef*1nUYOfUjwlAnwT(ljIjLRP&HF!&G_2tgJ9C2NY;ct054u4tFO(R zhTZ;j$S*?YOUXoNEwQZM`|Q#;&AAFj%X_PN>Kl5rK751)xxd@&n; zGh0EM7lB*#1IBvKuKgDSDxA-f^WQ!P0i7QkoBXjKZ^7IBWg1LK(9AV5F-xSDV4GJa zsYf818~ZTp>3cB7x!2R?yR@Esr^rVnXMzdxWd;-YG?3#?A$|Gmn%S?{iV5RamioiN z_!17Y>C?zDP+<5Uvxhx2oqZYSVn3VUYcOIQ%s)<^SeW^kCUeZzKy>xk$kZq*>FP;W;XQ$CH<`we7?O?6dW`5c2`vB-c%3s^<~TrA7Y0MSXn(ZzHwN0ftwL+7y}Br9>(7n*VO+7CZQaf= zV$mJxw(4GcTSJp0dJpPkYiK)+#t&bG+#!-%`qsK-J0nZW`7K^{m?7Gi-^0YC)x{@x zW-C-PKC{(v6C+!oej7Qghm3)L_7#yl-^8+wZoA#co!!Uq!FHD5NJc$@^i{7#NZQXD zdm~@(#d`iLx|-bU`DP%Ob3La;cDJJSNv-GA8~ycs7PKnY0vo!o>p9(E2@U$|In~?~ z5S7>5TzEaFn_CZOs`b1o7}}iu(N=gpr`sBDZM9e5{aGK3f6qe}_X>>R^_*_26*ZC8 zbE>VCuf46%dQLZVsWsHkdVb=RJnMP)&sfhL$nit#`JZ=$)^mjF!|Qnu9|Y^U=;!}W zt!MNjmxTG()a_19jfX(J`jzh<44bInwpiH|EPjV5FVXdVbJ*&3wqzY=-R;-kfq(3j zcXT3}gv-SkcQis7cb(tIkpU~>8n)Qzu!nAwwz#Nn%TQveHc$7~?1pGJ7yH~Wd_hIC zSB;nnuE^JTknvkotJtWwR<_rWXBsa*YcTSkBj z1v9%ExW*Q*028v_N75kU%Zk^5Nt*3}S?2WtzrMzMHTtQXXASyW8(-6)ZGKZH>>TmZmLWINl!mO_$I~RI zxvYtPtL1iCAdaKma!$D&4b{7P*|X_LpufTw?%N?1tLSKnZr5?4CEBWN)eyu$0!6w@ zRz0A?7Kuy&vm{Ma{W3LnfomWU&@#?mUxK5=s%9*O&G~4%aUk0 zzneEG9!9s~5Su(l)k%Hg;_0TU`+%!%Bwiqfa@#2tuB0PW2~AoV>h}GOI?vL0XYkA* zmQD)>P@_8xb9Me{WDRt_#C0B+2pASUEUV(=1}h&cuPqCo2-Z_?eu9yE z8N6<}{o>mpQa%A7;hVptnh~>v@XgQtp5nl*~ETFHug z?1?ZRk{M)U+$dVgjd3>y7^f@AvM~<7wGO|+ES&q*2CJ|)&iU2!!a0RmOXHj**vSw1 zIQK!}oCbk1UzdaD8o(8XGS?~|p;rqH`crd%rmZ@e#i zQ@{Ox8g{Io{y)%Ato}cczyC%3_J0zVDf`%e_~CnA3qSnIBLn7#zXV&@`8M{F6hC}4 zMg_(XyB)>niOY;yJMHhe^96BvDor$laxRw*`0%_8>ajGPoC{hwM%!`O z@9GS5*&=K1qO4|b58{)+VWio6(LI^NNV9i2B+!q5{1|GL5bymYhw3D28P@vj+JLo& zOJWSY8S5GhZjwg@Lf90KUg_Ng$~#{Az8&z=??h;wTL?Yj(;;5^y>vwwP-b@@KFF5= zFa2xM0WZCs^uLRj&b4XT`ss_GyAvqo$vACa4JEJiUaiSk z@g1D-WqO*bGPREFto;j0YrBUaobs`NAlNPQA~bL-b)5zNc^VSoAF1meF7Qv)3(zv< zBoRgI-i}1rX)kT zk8cCrV;gDt7nYL0mGlks=0s{=FGXZ}y)WeIJ$OpIcBNUYkT z<8|)jLZKpDJ%+=)u|Vbn_ly&ErwmayT}(mg24@z}j}>BT?DK`2YIEnSav~-@)m_(7 zVzLd`bkrUlb<4UAT8cXfGLO@8RF~uiH(rg+@#_DdH7ZI&FQA82sGCrAfRA~kU*Vnb zjY->nJ1~EQaj3L>e}r*OI8b<^4MB`$pEmeR$CI#Rr$=`$8?y;qj4W)`jZ6hIcds1U zFy#=>1)0V<_3k@Oox<^RDDKWbu;`MfLt_evM<;`Azp{EN!^eSWl#m%h`0h3vQEx1C z1F4CXZ#RQTuGrFDPfgE39?I5;JOKH4#U9-G-?c(C!FOU9PlayFcDlJ%eE=O0eb`QV ze@1EE3-~^TS|$bG+~D;|?_vNa@SeO$T{iFv{sh~uoFAJJg77g=KS;3;;f)4i*l&gV z!vj6O8;>o&$`MrQfNY_2f)L;otnwa(@&ak$wr-1a1jPsTn4Q4xTc67S_LfhCfZeh# z0JhmMk5_qMT}a0#k=~!M){5B+c+Z7_3B~Kw*5+f};q;jaFf3PmPLskJy8B5}7r!S1 zxjjSf_Jm<6$o+FzjsWyXy8LyLe9-XKa{+&R7+&{#U^4f!88BS7JOsl!G*J#=4Tei7 z-|pk<3ex)%hI;|OqwT zYw-xbD>S=#HgY3Jcx&o8w32>gS_Zsjs~YH3(MMHU;%BfCPZqX7oM!~ z6EmNg?%fGmg4NCtyev`iOqDmvRTrz5{bllCZ_gqo-yY)j+xaZxSHPAeRKnNSi5s*^ zdyY6W<&|?M933Iw>z1wWsXgBNp;fbyI#WF0Cht>m`c<#YP8m{jVp)%w+a~VyKb`v z6sbAdC5F@-<`M-ZEAC|qJ0;#uL~lDi+TdcO_fHuxoVfhS(36GV67l z^&9#4Y4Lh{#8Ai*Ha~Kmh089m927~IV~t9AM}11#$R--9^d5q)${MBqu1u(Wj5AE! zGLuWx_WRU}iVdS%tE3m*{}mR)aE=r+O1Ph{Y^|Pzdse zSP6v{N|tq=mHG8wVgYA9LvU^nyim`KeiC zPj3tt^`Fy9n0{kVo8e%Z%m4VJsECAwX@Bw~*BX&g9IH@ngj`2tDCrZKE_f`6%(0mz ze@SkocNnA>Tuok{oFjgt)XK!q9&T|zen1iS2XEUo!nEN`V*+=B#9F1Md$k`4(U=1v z6v<;n0QgQp?B?^F;zwF8`~(qNo$>_HXw@u!va zr4{pD7b8@gk3F=g6Z+<67Ea@T(|ooOh41p)hBgM4=T#5t!HL)t#?uTX#kiUzYKC z@+Z#cv)lVEWAl|&z9Gd0D#_@E@BM5sUii1ah55HsG~3lVquKV7uO0lIkbEs(onm_Y zFf1FqdoQyvENI`#;8EJDs@ETPkxt0dz2)dA919ewMGi}JE-2%Ms_Knzzlfc@%{vHc zUFjVTt466{tx&@IR3k9J;7IA4l{RtO2Jab;y1qE=y`K?u*Sq!Xg12n&PKBjN?ecBj zyCt2lRpm%(*-Na5$6)Ys@8>&!{PO0pZY})|WlMT34d=^1&UQL!?cv(b$CI9Y&EhK~ zwbxuZckidC-}RAQpwIO(8*t}dFGqpZCbrR1gHR0d2RE?wA}VAO*{xxVIVazH0ey@w z-?Q^&*Q3$rBV5=vzvOV;i{4#WlK2LnvzRQ_tP23?o^(yxyMpBDw;YFvt!rWHK}4@$ zF{wBz(k`M{wIQ5QwL`F}vwU65b`H$)^Ck#5Pc5b-g1WF_=JtC_z2l&h++G`-xn1>s z@!)9N!7~Ygs|?psWHfkr`c@+TeIVV1%SNVZc=l6yYj9-@q5=*O{XSfx&}HvKsAo@c z#@ap=aG}5PDp=tpLm|d7!wo zs=B!6vdDrHWVz}63V}^sGZOJqLou}vicQm*g(2=u3^l`_zWRUCe(V46bpOYFFjxOq zajx2@{tt&Do5W$+U5!Tpi(cY}bUdk#%9RGU@>>pFO6aHJ$PI5A*EH_Q&c)Oqq1BQJ zk(%S&MiZD0*{Q&Dr{zCEGdkaIWpU?6jDrt&DdyfW1cmPS(B=wmG2*hdZrRqz^_L~0 zTiK|*DldA4hFugdjm>O|M{!8bIC3QTMiSpD@5?3$a-v>zQ?^ODJ?E-<9EY#1y{6{U#c#l_n?aKMe6aP_#XLED-QIX`2ww?#&}gEtP3twQ#EQs; zj@^WIag%=$1hDfkhmMAbp0-AiiX!c<$ONO2J7P22?eg4Jt7z_)gM|4dpS+cH-Lm$` z(wlB!E$oO~zX*adG1`91kxLbGXkx{V#o%BF#iKh6Km8W&b1nR`UOZaTC=$hY6o}Y? zvc;pLJLuHW6-^FV(B1=c@hU$o22FF%utyXqqG?g%d{~pw#LV zvd-a4MW!qs-A0#>-V&S1axArFLNutZqh~t0C^&;Y=Ip+wiY%-XsY|lFb>4<+6NQqR+{w4mO6LTK^zd9sc`5i|I5v3v> znIpsbvfZacqe#!WvgYd9*S&Vq6W*V5`ip-`&}d-wv0z%PD_S{3m*r9yQ<%r5GGuZH z9meu>2Kd_WSr|wAL+FEH=(l~FjiR9aU1Nz>1b*v8{A&ptLR|>6Dqlse?ts_FTGFe2 z+mGA$r7+U?UHch>Jk>RodpY%6zXnorp^xA`*mff8%ZK3o_SfLG<4c+S8p?_17N#uiG--JI`bZB+I?`k_NKGV1>Ybs0{;g%khX; z!X)6~Tk=7u&-%8YuMzfmiEA_KThw=bnioewdd2(I{H-|0s;%o7Qp4e`sIH^1mV;e4 z&Cs5Nwr^g*-of){XF2{XbCvw<<2IOqo!ka6AKp)9mFn>% z*F&UcG*C_`>3v_sSPC&>!pv-+?&tpPA`XP+qb{ctb57^$xTRwCrLIDLk=W?L@s7;} z7e~CK5D?|2*zcGtie2c~$T6^(TDPLtTlp@a*E>khz3SR)=3RO9>?`)OOPS$A?(=!b z|Nl;{rbkc^`TBWZ1fBx8$N6D*mG=V>ne&6V?%LEv(PAh(7>Zj{8}gK;I$6W;wfn`s zBRINk4}kBU?u`Xt5~jOLe`VLwW;SndQ*9HYyBE)OT*|_VwrNaIe9A#%X&@cJ@OfmN zh*l;pjJ8eVx?nb0jx>i7Z8gRoMUka%j?F-flJQM+^l1O7Rg7Ex$i5u5Gx2Nq+3MH=on|G-#%J6V*>aY6#`ImJ4 z!+O{MmVwnj4UIMXYhv^GJ?QiP%5v+i&odGhf#s`ykQh?Z+nq__O7AltwNdGIE=)L` zrtTI_hmZxY$h327ZxFdEZ?O;bF))eMPvL8d5lh|@xx??ih>#SEs4Yo-l3r@G`b_(+EZu)g9+CsZYVlp%z@VSf019;Jw!oJ?)zst2#V5F z7+Gn#jv$RX2&!_=RT%`S&MLj>yR~#KAs)A*`1f07%~GX^anB!zg%mtjqijX%XT%&Zox;6 zMr-p0)G$GNV(kt-RPE`iSp^-c0VTwGA=l)j7M`(N;D)UPQ!|zc)}}4KKxvXpjZ(H) z)I8m;kUGr{WZ6LJ6SjpOK6!ia0JW3(6m!&b#2&XYUx7_vUM5a1A`H;AK|wC}fMK96 zf^&W_Wl$JgzKn3nef$s~I~l3&15p%BMuSjkcWqhlHPn^7(uoxw^_K+omqlvc4x#Y7 zvd-0Zo$Jc!lglW&ld;k-9c&(6BrgiWbe7ad)43l+J|yc61DupN0kzrVoj^qscTve# zg5u@gu@Xcz6^?uCNAw|l%gIx-G~-wxiP*&LS0;Y0=}zP*i763BzuT+4Z+zI$LohVK zgSz)q%2X~mL@O;t@4i8o{VGf!ugF&7lG6ND9VOte@=Yx4)>_SStcqI<+G9r4;t5fj zD(^=Oj~>@;)}sY?3h*Jx9q8@HEf-?6$LxEXhFKALFc-H>ngu)}ofg$Z<16>BfcY}e z)?QXEA2QMO?I3Wa_hSPK>|M1m&ChjXyxUFJ7QVGHmV4)NHbn5}mkJMa9fdIO8=5?d z4!|}*jjkr5G8`^ZiY}rh>)?#Y^#cHeqtUG;(C9ZIWe+ip$8maJ-n^A12#t8B`UTTy za^yBj2RvgJX$?*T^+?aDogcYw(Y0@c%C-;c^zVOV^s9qeHu|1%T}Sr$r2zF)iX3R= zi6m4<*by|f3nJB#!z1jxlblV?S2*JP8Vwo1s60|R=lg^)ym`djOc^aF8OKj?pH-8k z^N*;WLc9rSwJj)3l5IgLhYdRp1sh(uJOdk!m?>=Npd{FEwCXp(u-O@RP(FnZq_19l z#cLMeIr>j?2EPpPgxen^CqE+ z{^|n0ctR-xP2T1GZ&dX;X$6d`K7irO`$3a;7axdCm74~0M??(mNrCAaRq08AeZ3Dr zP$0;h(PQ;ZwC9VQ6BVnxXT^?Lrhnuu17ANdNBD{sua`CHN2UvPr&2Shdl`(VpgsaW zFSWIfZ&v}o%Shi%dj1=9Bcq$o_dFSr=Z~R3hV2cFN7I{rC-djptOd(e2Fukg(KUPq zEN^#z*113H^~d+)yUROnN@~XZye6;2^4eYT4)@2O7Ml+_{Natmq}KO|4l3xR&-eYZ)dwhr9ZOKO3PL{-9P7fr`hrAA`z~I50Pikss%XW3{ZyEuBNQ`XE6os4?_0) z{VR3->lfmE_HT$(O(A$xKhHp_C%k7)#2d*fscX&v$({2D0Fpl2`>a$qq4pM(Rqx)dilhxSRfi%X{^x59qvfC@KUNWBc-ru{urg;MxT+rSwH{Xe68P|tp^Os*o2_zDZ zk=_nAUKWim5My7BcEzH*V$t1%U>ZqHa*WwtxnLNqrXv&M>5ED84qH&_Zg1nH@hsv{ zWlJG}nxD!HXmhgbet!sV z{gFV$cJLhXoMY%u8n12vjJ)M-idT>;tRpN4~933ob-vmv!wvy zs2S?N4xOV86E~0{0vj^WhONDU>35z-Ei)ke6)&{Ic%k5;Gj`!(fXuYmVMl2;YhilD zc6=E0j4_vw?ol{M{{Zw>aQdH|e?!ONvZ=ypUx)G*iaM&S>N+SM;B*)1+516UY48za zZTQsOh$UGsj&P6TTpmH8LrA%?8kqR_tprr-Qf227jI6-+fs=)|KG6-hyZO}wl4_Q8mh?ThtUVB>4^0Wvw@SeT)aJoo|-%LD0hn()&x64*WQeHiXYFx3U(5t((U)Z;hI`evdFksGV$w8Ez59 zjs$Z{ERGusSJ&NYb?NA-G|9+HyF9mHCef-C^R;Bfd`dVeuiPGvMJwT7c%VQxlBBeu z0dB7Hw!p>LEo+8bKVDyyCMs5VjU2$?%%Q}3DuK@XN7?FPjG+>VsSLyW>#5EM11$@W zm(vIFO8(0S-;E@*{wiJsIiH16R(dB^2sesaqU$t(O~d)Y`93k@ko8|3IcatzHZ*?7 zDE&RZ@T+6=_w1thA!9A0I4ImQ<&gW30Hr?Wd1FRpYtu6n_Frz<>rC~`R z2h9mY17|}tY0e#Pn6rUJ>QuMFTlqEzt{Mc^&6VCZ&PFSvNw<(ABSFEZIaB98ZFik5 zY+OZOS<^3}=K&k>-IT_uh%ejdXDR91NH>$#7(Y*X9qAFImy=%Mm$`|w#-;LClh%X? zmY0*(==JTzq(4?W`>HEzZj8*h@w$2ETzmPv$h>Rj@@LUGS1m?!ad6lyl&AxhG z&Adg6BiG^jdBx>dUUyaP;tOhKFRH1%?!0TRtNni|-g*-N%5@(2tTaAhefsQ6gs|@V zcYVavopzBUBzbJyjDBiovHdACUas+9C((xPd(RaR7t`3TiBm6LOjH>37(_qr;vQ0N zP^vwEFF0Z(pJIK#f+YVe3P|@-Gu}#GEZxl6ik2KJYj8PrTd>G3j-7w8J

bdNJs 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 D+!k_@ literal 1746944 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∓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%0AKwACYkp|}|Kt1N+3`PmS!wg@h+ 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 P&l7l_!1DzDpC|Ai@aS^v diff --git a/pc/code_twain/sln/usb_tools/DlgScanner.cpp b/pc/code_twain/sln/usb_tools/DlgScanner.cpp index 6520473..e654070 100644 --- a/pc/code_twain/sln/usb_tools/DlgScanner.cpp +++ b/pc/code_twain/sln/usb_tools/DlgScanner.cpp @@ -11,7 +11,7 @@ #define TIMER_ID_REFRESH_BULK 1001 #include -#include +#include HMODULE g_my_inst; @@ -262,7 +262,7 @@ namespace sane return sod; } - SANE_Option_Descriptor* trans_json_to_opt_desc(json* jsn) + SANE_Option_Descriptor* trans_json_to_opt_desc(gb_json* jsn) { std::string title(""), desc(""), @@ -281,7 +281,7 @@ namespace sane if (val == "string") { - json* range = NULL, * child = NULL; + gb_json* range = NULL, * child = NULL; jsn->get_value("range", range); if (range) @@ -302,7 +302,7 @@ namespace sane } else if (val == "int" || val == "float") { - json* range = NULL; + gb_json* range = NULL; jsn->get_value("range", range); if (range) @@ -324,7 +324,7 @@ namespace sane else { std::vector constraints; - json* child = range->first_child(); + gb_json* child = range->first_child(); while(child) { @@ -351,7 +351,7 @@ namespace sane else { std::vector constraints; - json* child = range->first_child(); + gb_json* child = range->first_child(); while(child) { @@ -423,12 +423,12 @@ namespace sane strcmp(ret->name, SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM) == 0) ret->unit = SANE_UNIT_MM; - //bool enabled = true; - //if (jsn->get_value("enable", enabled) && !enabled) - // ret->cap |= SANE_CAP_INACTIVE; + bool enabled = true; + if (jsn->get_value("enabled", enabled) && !enabled) + ret->cap |= SANE_CAP_INACTIVE; // 关联�? - json* depend = NULL; + gb_json* depend = NULL; } return ret; @@ -449,7 +449,7 @@ namespace sane if (json_txt) { - json* jsn = new json(), * child = NULL; + gb_json* jsn = new gb_json(), * child = NULL; if (jsn->attach_text((char*)json_txt)) { child = jsn->first_child(); @@ -494,7 +494,16 @@ namespace sane if (action == SANE_ACTION_GET_VALUE && option > 0 && option <= g_opts.size()) { - dlg->get_option(g_opts[option - 1]->name, value, g_opts[option - 1]->size); + if (g_opts[option - 1]->type == SANE_TYPE_FIXED) + { + double val = .0f; + dlg->get_option(g_opts[option - 1]->name, &val, sizeof(val)); + *(SANE_Fixed*)value = SANE_FIX(val); + } + else + { + dlg->get_option(g_opts[option - 1]->name, value, g_opts[option - 1]->size); + } return SANE_STATUS_GOOD; } @@ -517,13 +526,26 @@ namespace sane else val_size = strlen((char*)value); - SANE_Status ret = (SANE_Status)dlg->set_option(g_opts[option - 1]->name, value, g_opts[option - 1]->type, val_size, g_opts[option - 1]->size, (int*)info); + SANE_Int after = 0; + SANE_Status ret = (SANE_Status)dlg->set_option(g_opts[option - 1]->name, value, g_opts[option - 1]->type, val_size, g_opts[option - 1]->size, (int*)&after); + + if (info) + *info = after; if (buf == &val) { *(SANE_Int*)value = SANE_FIX(val); } + if (after & SANE_INFO_RELOAD_OPTIONS) + { + std::string str(""); + if (dlg->get_all_option(str) == 0) + { + reset_opts(str.c_str()); + } + } + return ret; } @@ -740,8 +762,17 @@ void CDlgScanner::set_device(usb::LPUSBPNP pnp) std::string root(usb::u2a(img_root_.c_str())); char name[40] = { 0 }; int err = 0; + std::string ext("jpg"); - sprintf_s(name, _countof(name) - 1, "scan_%04d.jpg", ++img_cnt_); + if (img->format == IMG_FMT_BMP) + ext = "bmp"; + else if (img->format == IMG_FMT_GIF) + ext = "gif"; + else if (img->format == IMG_FMT_PNG) + ext = "png"; + else if (img->format == IMG_FMT_TIFF) + ext = "tiff"; + sprintf_s(name, _countof(name) - 1, "scan_%04d.%s", ++img_cnt_, ext.c_str()); err = saver->open((root + name).c_str(), size); log_cls::log(LOG_LEVEL_DEBUG, "Begin receiving new image (%s + %llu) = %d\r\n", (root + name).c_str(), size, err); if (err) @@ -843,6 +874,17 @@ void CDlgScanner::get_option(const char* name, void* value, size_t size) { scanner_->option_value_get(name, value, size); } +int CDlgScanner::get_all_option(std::string& opts_json) +{ + int ret = scanner_->option_get_all(opts_json); + + if (ret == 0) + { + scanner_handler::reorder_device_config_json(opts_json); + } + + return ret; +} int CDlgScanner::set_option(const char* name, void* value, int type, size_t len, size_t max_len, int* after) { return scanner_->option_value_set(name, type, value, max_len, len, (uint8_t*)after); diff --git a/pc/code_twain/sln/usb_tools/DlgScanner.h b/pc/code_twain/sln/usb_tools/DlgScanner.h index 965e46f..e3d0e43 100644 --- a/pc/code_twain/sln/usb_tools/DlgScanner.h +++ b/pc/code_twain/sln/usb_tools/DlgScanner.h @@ -89,6 +89,7 @@ protected: public: void set_device(usb::LPUSBPNP pnp); void get_option(const char* name, void* value, size_t size); + int get_all_option(std::string& opts_json); int set_option(const char* name, void* value, int type, size_t len, size_t max_len, int* after); public: diff --git a/pc/code_twain/sln/usb_tools/scanner/scanner_handler.cpp b/pc/code_twain/sln/usb_tools/scanner/scanner_handler.cpp index b681a2d..9d394d7 100644 --- a/pc/code_twain/sln/usb_tools/scanner/scanner_handler.cpp +++ b/pc/code_twain/sln/usb_tools/scanner/scanner_handler.cpp @@ -3,7 +3,7 @@ #include "./usb/async_usb_host.h" #include -#include +#include @@ -259,7 +259,7 @@ bool scanner_handler::reorder_device_config_json(std::string& cont, const std::m typedef struct _grp_item { std::string name; - std::vector items; + std::vector items; bool operator==(const char* gn) { @@ -267,8 +267,8 @@ bool scanner_handler::reorder_device_config_json(std::string& cont, const std::m } }GRPITEM; std::vector items; - std::vector nogrp; - json* jsn = new json(), * child = nullptr; + std::vector nogrp; + gb_json* jsn = new gb_json(), * child = nullptr; bool ret = jsn->attach_text(&cont[0]); int cnt = 0; @@ -299,14 +299,14 @@ bool scanner_handler::reorder_device_config_json(std::string& cont, const std::m { nogrp.push_back(child); } - + child = jsn->next_child(); } jsn->release(); - child = new json(); + child = new gb_json(); child->set_value("option_count", cnt); - jsn = new json(); + jsn = new gb_json(); jsn->set_value("global", child); child->release(); @@ -326,7 +326,7 @@ bool scanner_handler::reorder_device_config_json(std::string& cont, const std::m if (it == items.end()) continue; - child = new json(); + child = new gb_json(); child->set_value("category", "base"); child->set_value("type", "group"); child->set_value("title", v.second.c_str()); @@ -344,7 +344,7 @@ bool scanner_handler::reorder_device_config_json(std::string& cont, const std::m for (auto& v : items) { - child = new json(); + child = new gb_json(); child->set_value("category", "base"); child->set_value("type", "group"); child->set_value("title", v.name.c_str()); diff --git a/pc/code_twain/sln/usb_tools/scanner/scanner_handler.h b/pc/code_twain/sln/usb_tools/scanner/scanner_handler.h index ba58747..df7f0c8 100644 --- a/pc/code_twain/sln/usb_tools/scanner/scanner_handler.h +++ b/pc/code_twain/sln/usb_tools/scanner/scanner_handler.h @@ -93,7 +93,7 @@ class scanner_handler : public refer public: scanner_handler(void); - // the json text from device only contains option items, the "group" info is contains in every item. + // the gb_json text from device only contains option items, the "group" info is contains in every item. // this function convert them into normal SANE-OPTION JSON // the parameter 'groups' is given the sequence of group static bool reorder_device_config_json(std::string& cont, const std::map* groups = nullptr); diff --git a/pc/code_twain/sln/usb_tools/usb_tools.vcxproj b/pc/code_twain/sln/usb_tools/usb_tools.vcxproj index 5e50a1c..e4bb095 100644 --- a/pc/code_twain/sln/usb_tools/usb_tools.vcxproj +++ b/pc/code_twain/sln/usb_tools/usb_tools.vcxproj @@ -29,14 +29,14 @@ Application true - v143 + v142 Unicode Dynamic Application false - v143 + v142 true Unicode Dynamic @@ -44,14 +44,14 @@ Application true - v143 + v142 Unicode Dynamic Application false - v143 + v142 true Unicode Dynamic @@ -77,7 +77,7 @@ true $(ProjectDir)..\..\..\sdk\include\;$(ProjectDir)..\..\device\win_usb\;$(ProjectDir)..\sdk\include\;$(ProjectDir)..\..\..\..\device\gxx-linux\usb\src\common\;$(IncludePath) - $(ProjectDir)..\sdk\lib\$(Configuration);$(ProjectDir)..\..\..\sdk\lib\win\$(PlatformTarget)\oem\huagao;$(LibraryPath) + $(SolutionDir)sdk\lib\$(Configuration);$(ProjectDir)..\..\..\sdk\lib\win\$(PlatformTarget)\oem\huagao;$(LibraryPath) true @@ -87,7 +87,7 @@ false $(ProjectDir)..\..\..\sdk\include\;$(ProjectDir)..\..\device\win_usb\;$(ProjectDir)..\sdk\include\;$(ProjectDir)..\..\..\..\device\gxx-linux\usb\src\common\;$(IncludePath) - $(ProjectDir)..\sdk\lib\$(Configuration);$(ProjectDir)..\..\..\sdk\lib\win\$(PlatformTarget)\oem\huagao;$(LibraryPath) + $(SolutionDir)sdk\lib\$(Configuration);$(ProjectDir)..\..\..\sdk\lib\win\$(PlatformTarget)\oem\huagao;$(LibraryPath) false @@ -200,7 +200,7 @@ - + @@ -246,9 +246,8 @@ NotUsing NotUsing - + NotUsing - NotUsing NotUsing diff --git a/pc/code_twain/sln/usb_tools/usb_tools.vcxproj.filters b/pc/code_twain/sln/usb_tools/usb_tools.vcxproj.filters index 3d650df..c8df840 100644 --- a/pc/code_twain/sln/usb_tools/usb_tools.vcxproj.filters +++ b/pc/code_twain/sln/usb_tools/usb_tools.vcxproj.filters @@ -81,9 +81,6 @@ Imports - - Imports - scanner @@ -105,6 +102,9 @@ opt-ui + + Imports + @@ -149,9 +149,6 @@ Imports - - Imports - scanner @@ -173,6 +170,9 @@ opt-ui + + Imports + diff --git a/pc/code_twain/sln/usb_tools/usb_toolsDlg.cpp b/pc/code_twain/sln/usb_tools/usb_toolsDlg.cpp index f3f8848..28877b3 100644 --- a/pc/code_twain/sln/usb_tools/usb_toolsDlg.cpp +++ b/pc/code_twain/sln/usb_tools/usb_toolsDlg.cpp @@ -267,12 +267,273 @@ namespace usb } +namespace test +{ + enum data_type1 + { + DATA_TYPE_BOOL = 0, // (bool*) + DATA_TYPE_INT1, // (uint8_t*) + DATA_TYPE_INT2, // (uint16_t*) + DATA_TYPE_INT4, // (uint32_t*) + DATA_TYPE_INT8, // (uint64_t*) + DATA_TYPE_FLOAT, // (double*) + DATA_TYPE_STRING, // (char*) with max_len space + DATA_TYPE_CUSTOM, + }; + + data_type1 type_from_string(const char* type_desc) + { + if (strcmp(type_desc, "bool") == 0) + return DATA_TYPE_BOOL; + if (strcmp(type_desc, "int") == 0) + return DATA_TYPE_INT4; + if (strcmp(type_desc, "float") == 0) + return DATA_TYPE_FLOAT; + if (strcmp(type_desc, "string") == 0) + return DATA_TYPE_STRING; + + return DATA_TYPE_CUSTOM; + } + bool try_equal(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt, bool* result) + { + bool oper_not = false, calc = true, handled = false; + size_t pos = exp.find("=="); + + if (pos == std::string::npos) + { + pos = exp.find("!="); + if (pos != std::string::npos) + { + oper_not = true; + } + } + if (pos != std::string::npos) + { + handled = true; + if (pos) + { + std::string types(""); + char buf[40] = { 0 }, * mem = nullptr; + size_t l = sizeof(buf) - 1; + + *name = exp.substr(0, pos); + get_opt(name->c_str(), buf, &l, "type"); + *type = type_from_string(buf); + l = 0; + get_opt(name->c_str(), mem, &l, "cur"); + mem = new char[l + 4]; + l += 4; + get_opt(name->c_str(), mem, &l, "cur"); + *val = std::string(mem, l); + delete[] mem; + } + exp.erase(0, pos + 2); + + if (*type == DATA_TYPE_BOOL) + { + calc = *(bool*)val->c_str() == (exp == "true"); + } + else if (*type == DATA_TYPE_INT4) + { + // in range ? + if (exp[0] == '[') + { + int lower = atoi(exp.c_str() + 1), + upper = 0; + pos = exp.find(","); + if (pos++ != std::string::npos) + upper = atoi(exp.c_str() + pos); + calc = lower <= *(int*)val->c_str() && *(int*)val->c_str() <= upper; + } + else + { + calc == *(int*)val->c_str() == atoi(exp.c_str()); + } + } + else if (*type == DATA_TYPE_FLOAT) + { + // in range ? + if (exp[0] == '[') + { + double lower = atof(exp.c_str() + 1), + upper = 0; + pos = exp.find(","); + if (pos++ != std::string::npos) + upper = atof(exp.c_str() + pos); + calc = lower <= *(double*)val->c_str() && *(double*)val->c_str() <= upper; + } + else + { + calc = IS_FLOAT_EQUAL(*(double*)val->c_str(), atof(exp.c_str())); + } + } + else if (*type == DATA_TYPE_STRING) + { + calc = *val == exp; + } + else + { + log_cls::log(LOG_LEVEL_FATAL, "Logic-operation error: un-supported type(%d) in '%s%s'\n", *type, oper_not ? "!=" : "==", exp.c_str()); + } + + *result = oper_not ^ calc; + } + + return handled; + } + bool try_great(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt, bool* result) + { + bool oper_not = false, calc = true, handled = false; + size_t pos = exp.find(">"); + + if (pos == std::string::npos) + { + pos = exp.find("<="); + if (pos != std::string::npos) + { + oper_not = true; + } + } + if (pos != std::string::npos) + { + handled = true; + if (pos) + { + std::string types(""); + char buf[40] = { 0 }, * mem = nullptr; + size_t l = sizeof(buf) - 1; + + *name = exp.substr(0, pos); + get_opt(name->c_str(), buf, &l, "type"); + *type = type_from_string(buf); + l = 0; + get_opt(name->c_str(), mem, &l, "cur"); + mem = new char[l + 4]; + l += 4; + get_opt(name->c_str(), mem, &l, "cur"); + *val = std::string(mem, l); + delete[] mem; + } + exp.erase(0, pos + 1 + oper_not); + + if (*type == DATA_TYPE_INT4) + { + calc == *(int*)val->c_str() > atoi(exp.c_str()); + } + else if (*type == DATA_TYPE_FLOAT) + { + calc = *(double*)val->c_str() > atof(exp.c_str()); + } + else + { + log_cls::log(LOG_LEVEL_FATAL, "Logic-operation error: un-supported type(%d) in '%s%s'\n", *type, oper_not ? "<=" : ">", exp.c_str()); + } + + *result = oper_not ^ calc; + } + + return handled; + } + bool try_less(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt, bool* result) + { + bool oper_not = false, calc = true, handled = false; + size_t pos = exp.find("<"); + + if (pos == std::string::npos) + { + pos = exp.find(">="); + if (pos != std::string::npos) + { + oper_not = true; + } + } + if (pos != std::string::npos) + { + handled = true; + if (pos) + { + std::string types(""); + char buf[40] = { 0 }, * mem = nullptr; + size_t l = sizeof(buf) - 1; + + *name = exp.substr(0, pos); + get_opt(name->c_str(), buf, &l, "type"); + *type = type_from_string(buf); + l = 0; + get_opt(name->c_str(), mem, &l, "cur"); + mem = new char[l + 4]; + l += 4; + get_opt(name->c_str(), mem, &l, "cur"); + *val = std::string(mem, l); + delete[] mem; + } + exp.erase(0, pos + 1 + oper_not); + + if (*type == DATA_TYPE_INT4) + { + calc == *(int*)val->c_str() < atoi(exp.c_str()); + } + else if (*type == DATA_TYPE_FLOAT) + { + calc = *(double*)val->c_str() < atof(exp.c_str()); + } + else + { + log_cls::log(LOG_LEVEL_FATAL, "Logic-operation error: un-supported type(%d) in '%s%s'\n", *type, oper_not ? ">=" : "<", exp.c_str()); + } + + *result = oper_not ^ calc; + } + + return handled; + } + bool is_depends_item_ok(std::string& exp, std::string* name, int* type, std::string* val, std::function get_opt) + { + // ==, >, < + // !=, <=, >= + bool ok = true; + + if (!try_equal(exp, name, type, val, get_opt, &ok)) + { + if (!try_great(exp, name, type, val, get_opt, &ok)) + { + try_less(exp, name, type, val, get_opt, &ok); + } + } + + + return ok; + } +} + CusbtoolsDlg::CusbtoolsDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_USB_TOOLS_DIALOG, pParent) { log_cls::initialize(NULL); log_cls::log(LOG_LEVEL_DEBUG, "--------------------New instance started ...--------------------\r\n"); + auto get_opt_val = [&](const char* cfg_name, void* buf, size_t* len, const char* key) -> int32_t + { + if (strcmp(key, "type") == 0) + strcpy((char*)buf, "bool"); + else if (strcmp(key, "cur") == 0) + { + if (*len < 1) + { + *len = 1; + return ENOMEM; + } + + *(bool*)buf = false; + *len = sizeof(bool); + } + + return 0; + }; + std::string exp("is-check-dog-ear==true"), name(""), val(""); + int type = 0; + bool chk = test::is_depends_item_ok(exp, &name, &type, &val, get_opt_val); + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); }

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