[
  {
    "path": ".gitignore",
    "content": ".pioenvs\n.piolibdeps\n.clang_complete\n.gcc-flags.json\n.pio\n.vscode\n.DS_Store\n.idea\nSolderingPen_ESP32S2/build\nSolderingPen_ESP32S2/.idea"
  },
  {
    "path": "README.md",
    "content": "# Songguo PTS200 \n## Introduction\n1. PD3.0 and QC3 fast charge protocol\n\n2. 20V 5A 100W maximum power\n<!-- 内置IMU，用于休眠检测 -->\n3. Built-in IMU for sleep detection\n<!-- PD协议芯片使用CH224K -->\n4. PD protocol chip uses CH224K\n<!-- MOSFET支持30V 12A -->\n5. MOSFET supports 30V 12A\n<!-- MCU使用ESP32 S2 FH4 -->\n6. MCU uses ESP32 S2 FH4\n<!-- 电源输入使用功率加强的USB-C接口 -->\n7. The power input uses a power-enhanced USB-C interface\n<!-- 定制的4欧姆内阻的烙铁头 -->\n8. Customized soldering tip with 4 ohm internal resistance. It can be powered by 20V with 100W.\n<!-- 128x64 OLED screen -->\n9. 128x64 OLED screen\n<!-- 3个按键，中间的按键与GPIO0相连 -->\n10. 3 buttons, the middle button is connected to GPIO0\n<!-- MSC 模式的固件升级，闪存盘模式 -->\n11. MSC firmware upgrade, flash disk mode\n<!-- 带有便携式的尖端保护盖 -->\n12. With a portable tip cap\n\n<!-- 构建方法 -->\n## Build method\n<!-- Arduino with ESP32 环境 -->\n1. Arduino with ESP32 environment\n<!-- 安装依赖库 -->\n2. Install dependent libraries: Button2, U8g2, QC3Control, ESP32AnalogRead, PID_v1, SparkFun_LIS2DH12\n<!-- 从U8G2库中替换u8g2_fonts.c文件 -->\n3. Replace the u8g2_fonts.c file from the U8G2 library\n<!-- 在Arduino 中选择Tools- USB CDC On Boot- Enable -->\n4. In Arduino, select Tools-USB CDC On Boot-Enable\n<!-- 在Arduino 中选择Tools-Upload Mode- Internal USB -->\n5. In Arduino, select Tools-Upload Mode-Internal USB\n<!-- 点击上传 -->\n6. Click Upload"
  },
  {
    "path": "SolderingPen_ESP32S2/Languages.h",
    "content": "// 菜单项\nconst uint8_t language_types = 3;\n//                                            \"温控类型\",   \"溫控類型\",   \"Control Type\",\n\nconst char *SetupItems[][language_types] = { \"菜单设置\", \"菜單設置\", \"Setup Menu\",\n                                             \"烙铁头设置\", \"烙鐵頭設置\", \"Tip Settings\",\n                                             \"温度设置\", \"溫度設置\", \"Temp Settings\",\n                                             \"时间设置\", \"時間設置\", \"Timer Settings\",\n                                             \"主屏幕\", \"主屏幕\", \"Main Screen\",\n                                             \"信息\", \"信息\", \"Information\",\n                                             \"电压设置\", \"電壓設置\", \"Voltage\",\n                                             \"QC\", \"QC\", \"QC\",\n                                             \"蜂鸣器\", \"蜂鳴器\", \"Buzzer\",\n                                             \"恢复默认设置\", \"恢復默認設置\", \"Restore Config\",\n                                             \"更新版本\", \"更新版本\", \"Update Firmware\",\n                                             \"Languages\", \"Languages\", \"Languages\",\n                                             \"切换左右手\", \"切换左右手\", \"L/R Hand\",\n                                             \"返回\", \"返回\", \"Return\" };\nconst char *LanguagesItems[][language_types] = { \"Languages\", \"Languages\", \"Languages\",\n                                                 \"简体中文\", \"简体中文\", \"zh-CN\",\n                                                 \"繁体中文\", \"繁体中文\", \"zh-TW\",\n                                                 \"English\", \"English\", \"English\" };\nconst char *TipItems[][language_types] = { \"烙铁头:\", \"烙鐵頭:\", \"Tip:\",\n                                           \"更换烙铁头\", \"更換烙鐵頭\", \"Change Tip\",\n                                           \"校准烙铁头\", \"校準烙鐵頭\", \"Calibrate Tip\",\n                                           \"重命名烙铁头\", \"重命名烙鐵頭\", \"Rename Tip\",\n                                           \"删除烙铁头\", \"刪除烙鐵頭\", \"Delete Tip\",\n                                           \"新建烙铁头\", \"新建烙鐵頭\", \"New Tip\",\n                                           \"返回\", \"返回\", \"Return\" };\nconst char *TempItems[][language_types] = { \"温度设置\", \"溫度設置\", \"Temp Settings\",\n                                            \"默认温度\", \"默認溫度\", \"Default Temp\",\n                                            \"休眠温度\", \"休眠溫度\", \"Sleep Temp\",\n                                            \"提高温度\", \"提高溫度\", \"Boost Temp\",\n                                            \"返回\", \"返回\", \"Return\" };\nconst char *TimerItems[][language_types] = { \"时间设置\", \"時間設置\", \"Timer Settings\",\n                                             \"休眠时间\", \"休眠時間\", \"Sleep Timer\",\n                                             \"关闭时间\", \"關閉時間\", \"Shutdown Timer\",\n                                             \"提温时间\", \"提溫時間\", \"Boost Timer\",\n                                             \"唤醒阈值\", \"唤醒閾值\", \"Wake Threshold\",\n                                             \"返回\", \"返回\", \"Return\" };\nconst char *ControlTypeItems[][language_types] = { \"温控类型\", \"溫控類型\", \"Control Type\",\n                                                   \"非PID\", \"非PID\", \"Non-PID\",\n                                                   \"PID\", \"PID\", \"PID\" };\nconst char *MainScreenItems[][language_types] = {\n  \"主屏幕\",\n  \"主屏幕\",\n  \"Main Screen\",\n  \"大数字\",\n  \"大數字\",\n  \"Big Number\",\n  \"更多信息\",\n  \"更多信息\",\n  \"More Info\",\n};\nconst char *StoreItems[][language_types] = { \"存储设置?\", \"存儲設置?\", \"Save?\",\n                                             \"否\", \"否\", \"No\",\n                                             \"是\", \"是\", \"Yes\" };\nconst char *DefaultItems[][language_types] = { \"恢复设置?\", \"恢復設置?\", \"Restore?\",\n                                               \"否\", \"否\", \"No\",\n                                               \"是\", \"是\", \"Yes\" };\nconst char *SureItems[][language_types] = { \"确定?\", \"確定?\", \"Sure?\",\n                                            \"否\", \"否\", \"No\",\n                                            \"是\", \"是\", \"Yes\" };\nconst char *VoltageItems[][language_types] = { \"电压设置\", \"電壓設置\", \"Voltage Settings\",\n                                               \"9V\", \"9V\", \"9V\",\n                                               \"12V\", \"12V\", \"12V\",\n                                               \"15V\", \"15V\", \"15V\",\n                                               \"20V(50%)\", \"20V(50%)\", \"20V(50%)\",\n                                               \"20V(100%)\", \"20V(100%)\", \"20V(100%)\"};\nconst char *QCItems[][language_types] = { \"QC\", \"QC\", \"QC\",\n                                          \"禁用\", \"禁用\", \"Disable\",\n                                          \"启用\", \"啟用\", \"Enable\" };\nconst char *BuzzerItems[][language_types] = { \"蜂鸣器\", \"蜂鳴器\", \"Buzzer\",\n                                              \"禁用\", \"禁用\", \"Disable\",\n                                              \"启用\", \"啟用\", \"Enable\" };\nconst char *DefaultTempItems[][language_types] = { \"默认温度\", \"默認溫度\", \"Default Temp\",\n                                                   \"deg C\", \"deg C\", \"deg C\" };\nconst char *SleepTempItems[][language_types] = { \"休眠温度\", \"休眠溫度\", \"Sleep Temp\",\n                                                 \"deg C\", \"deg C\", \"deg C\" };\nconst char *BoostTempItems[][language_types] = { \"提高温度\", \"提高溫度\", \"Boost Temp\",\n                                                 \"deg C\", \"deg C\", \"deg C\" };\nconst char *SleepTimerItems[][language_types] = { \"休眠时间\", \"休眠時間\", \"Sleep Timer\",\n                                                  \"秒\", \"秒\", \"sec\" };\nconst char *WAKEUPthresholdItems[][language_types] = { \"唤醒阈值\", \"唤醒閾值\", \"Wake Threshold\",\n                                                       \"mg\", \"mg\", \"mg\" };\nconst char *OffTimerItems[][language_types] = { \"关闭时间\", \"關閉時間\", \"Shutdown Timer\",\n                                                \"分钟\", \"分鐘\", \"min\" };\nconst char *BoostTimerItems[][language_types] = { \"提温时间\", \"提溫時間\", \"Boost Timer\",\n                                                  \"秒\", \"秒\", \"sec\" };\nconst char *DeleteMessage[][language_types] = { \"警告\", \"警告\", \"Warning\",\n                                                \"你不能\", \"你不能\", \"You can't\",\n                                                \"删除你的\", \"刪除你的\", \"delete your\",\n                                                \"最后的烙铁头!\", \"最後的烙鐵頭!\", \"last tip!\" };\nconst char *MaxTipMessage[][language_types] = { \"警告\", \"警告\", \"Warning\",\n                                                \"你已达\", \"你已達\", \"You reached\",\n                                                \"最大数量\", \"最大數量\", \"maximum number\",\n                                                \"的烙铁头!\", \"的烙鐵頭!\", \"of tips!\" };\n\nconst char *txt_set_temp[] = { \"设温:\", \"設溫:\", \"SET:\" };\nconst char *txt_error[] = { \"错误\", \"錯誤\", \"ERROR\" };\nconst char *txt_off[] = { \"关闭\", \"關閉\", \"OFF\" };\nconst char *txt_sleep[] = { \"休眠\", \"休眠\", \"SLEEP\" };\nconst char *txt_boost[] = { \"提温\", \"提溫\", \"BOOST\" };\nconst char *txt_worky[] = { \"工作\", \"工作\", \"WORK\" };\nconst char *txt_on[] = { \"加热\", \"加熱\", \"HEAT\" };\nconst char *txt_hold[] = { \"保持\", \"保持\", \"HOLD\" };\n\nconst char *txt_Deactivated[] = { \"禁用\", \"禁用\", \"Deactivated\" };\n\nconst char *txt_temp[] = { \"温度:\", \"溫度:\", \"TEMP:\" };\nconst char *txt_voltage[] = { \"电压:\", \"電壓:\", \"VOLT:\" };\nconst char *txt_Version[] = { \"版本:\", \"版本:\", \"VER:\" };\n\nconst char *txt_select_tip[] = { \"选择烙铁头\", \"選擇烙鐵頭\", \"Select Tip\" };\n\nconst char *txt_calibrate[] = { \"校准\", \"校準\", \"Calibrate\" };\nconst char *txt_step[] = { \"步进\", \"步進\", \"Step\" };\nconst char *txt_set_measured[] = { \"设为测量\", \"設為測量\", \"Set Measure\" };\nconst char *txt_s_temp[] = { \"的温度:\", \"的溫度:\", \"Temp:\" };\nconst char *txt_temp_2[] = { \"温度：  \", \"溫度：  \", \"Temp:  \" };\nconst char *txt_wait_pls[] = { \"请稍等...\", \"請稍等...\", \"Please wait ...\" };\n\nconst char *txt_enter_tip_name[] = { \"输入烙铁头名称\", \"輸入烙鐵頭名稱\", \"Enter Tip Name\" };\n"
  },
  {
    "path": "SolderingPen_ESP32S2/PTS200_16.h",
    "content": "/*\n  Fontname: -FreeType-Alibaba PuHuiTi Medium-Medium-R-Normal--16-120-96-96-P-142-ISO10646-1\n  Copyright: Copyright � 2019 Alibaba (China) Co., Ltd. All rights reserved.\n  Glyphs: 244/28936\n  BBX Build Mode: 0\n*/\n// #include \"U8g2lib.h\"\n\nconst uint8_t PTS200_16[7917] U8G2_FONT_SECTION(\"PTS200_16\") = \n  \"\\365\\0\\3\\2\\4\\5\\4\\5\\6\\20\\21\\377\\375\\13\\375\\15\\377\\1\\324\\4\\1\\5\\234 \\6\\0\\20\\242\\0!\\10\\341\"\n  \"\\366\\241x\\210\\4\\42\\12\\65R\\243P\\224HJ\\0#\\30\\310\\20\\242\\213\\302(\\214\\242a\\210\\212Q\\30\\205Q\"\n  \"\\64\\14Q\\61\\12\\243\\14$\\24\\327\\360\\241K\\267\\244)\\222\\302$]\\223\\60\\222*mk\\6%\\27\\327\\360\\241\"\n  \"\\321\\244\\244\\224\\224\\64%\\215\\323\\70\\221\\222()I\\221\\246\\0&\\25\\307\\20\\242\\22\\243,\\312\\222\\64\\216*M\"\n  \"I-\\312\\242J\\244\\5'\\10\\62V\\243P\\24\\0(\\14\\344\\362\\241\\213jQ\\326c\\26\\26)\\15\\344\\364\\241\"\n  \"\\10ka\\326S\\26\\325\\0*\\17\\227P\\242\\213\\263\\250\\322\\266%M\\265\\70\\3+\\24\\251.\\242\\314\\221\\34\\311\"\n  \"\\221p\\70\\346H\\216\\344H\\216\\204\\0,\\10B\\324\\241\\30\\22\\5-\\7\\27\\320\\242\\70\\4.\\7\\42\\364\\241\\30\"\n  \"\\2/\\17\\306\\22\\242-\\246a\\32\\246a\\32\\246)\\0\\60\\15\\267\\22\\252\\332*\\251_\\223,\\233\\0\\61\\11\\265\"\n  \"\\26\\252\\30\\373\\247A\\62\\15\\267\\22\\252\\332*i\\134\\355u\\30\\2\\63\\23\\267\\22\\252\\31\\242\\60\\7\\342\\64\\333\\201\"\n  \"\\34\\210\\305h\\210\\0\\64\\25\\270\\22\\252\\215\\325$\\214\\262R\\30\\205\\321\\60\\250\\71\\220\\3\\21\\0\\65\\20\\267\\22\\252\"\n  \"\\270\\304-\\223\\226\\3q,FC\\4\\66\\20\\267\\22\\252\\332*qe\\322\\222\\324\\232d\\331\\4\\67\\15\\267\\22\\252\"\n  \"\\70\\304i\\134\\215\\253q\\15\\70\\21\\267\\22\\252\\332JY\\224e[%\\265&Y\\66\\1\\71\\20\\267\\22\\252\\332*\"\n  \"\\251\\65\\311\\244%\\256d\\331\\4:\\11\\202V\\242\\30rd\\10;\\13\\262\\366\\241\\30rlH\\24\\0<\\21\\327\"\n  \"\\360\\241N\\373\\16\\344@\\16\\344@\\16\\344@\\0=\\12G\\220\\242\\70\\344\\204C\\0>\\21\\327\\360\\241\\310\\201\\34\"\n  \"\\310\\201\\34\\310\\201\\34H\\373\\14\\77\\16\\306\\22\\242\\322\\242$\\24[\\353\\264\\64\\2@\\24\\230\\60\\242\\32\\262\\60\\211\"\n  \"\\214\\211\\264(Q\\42-\\305l\\210\\0A\\27\\271\\20\\252\\314\\221\\34H\\342$\\315\\302\\254\\32\\15C\\224&\\71\\240\"\n  \"\\3\\1B\\22\\267\\22\\252\\30\\244\\60I\\215\\311 \\205IjL\\6\\11C\\26\\270\\22\\252\\33\\262\\60\\211s \\7\"\n  \"r \\7r$G\\302lH\\0D\\30\\271\\22\\262\\70Dq\\222\\3:\\240\\3:\\240\\3:\\240\\3r\\62\\14\"\n  \"\\21\\0E\\16\\267\\22\\246\\70\\310\\315\\303 \\67\\17C\\0F\\14\\267\\22\\246\\70\\310\\315\\303\\22w\\6G\\27\\271\\22\"\n  \"\\262\\32\\246XGr$G\\302A\\7t@\\7\\222\\70\\32\\206\\0H\\26\\271\\22\\256\\310\\1\\35\\320\\1\\35\\320\\201\"\n  \"\\7\\35\\320\\1\\35\\320\\1\\35\\10I\\7\\261\\24\\222x\\20J\\12\\344\\256\\221\\353\\377\\224H\\0K\\23\\270\\22\\252\\210\"\n  \"\\325$\\214\\262R\\270FaV\\214\\322$\\16L\\12\\267\\22\\242\\210\\373\\347a\\10M\\34\\273\\22\\266\\320\\201!\\7\"\n  \"\\226\\64Q\\322D\\312\\42)\\213\\264$\\323\\222L\\14uH\\207\\2N\\24\\270\\22\\256PW%TB)\\223\\62\"\n  \"-\\322\\42\\61\\21\\23UO\\27\\272\\22\\262\\33\\322\\60\\213\\223\\34\\321\\21\\35\\321\\21\\35)ga:d\\0P\\15\"\n  \"\\267\\22\\246\\270\\244^\\207!\\211\\233\\1Q\\32\\332\\322\\261\\33\\322\\60\\213\\223\\34\\321\\21\\35\\321\\21\\35)ga:\"\n  \"\\344X\\216%\\0R\\25\\270\\22\\252\\70\\245I\\232\\244I\\30\\15Z\\30\\205Q\\232\\244I\\34S\\22\\267\\22\\252\\332\"\n  \"*q\\16\\344\\300\\16\\344@,FC\\4T\\25\\271\\20\\246x\\314\\221\\34\\311\\221\\34\\311\\221\\34\\311\\221\\34\\311\\221\"\n  \"\\20U\\14\\270\\22\\256\\210\\375s\\22fC\\4V\\27\\271\\20\\252\\310\\1\\35\\320\\201$\\215\\322\\254\\230\\245I\\234\\344\"\n  \"@\\216\\204\\0W\\37\\275\\22\\276HS\\65U+Y\\222EY\\222EY\\222U\\262$L\\262$L\\262$-\"\n  \"\\247\\31\\0X\\27\\271\\22\\252\\310\\1\\35H\\322\\254\\232\\344@\\16$iVMr@\\7\\2Y\\20\\267\\22\\246H\"\n  \"\\325$\\213\\262J\\230\\244q\\67\\0Z\\16\\270\\22\\252\\70\\350@\\334\\357@\\16\\34\\4[\\12\\344\\364\\241\\30\\264\\376\"\n  \"\\267!\\134\\24\\347\\360\\241\\210s \\316\\201\\70\\7\\342\\34\\210s \\316\\201\\70]\\12\\344\\364\\241\\30\\262\\376\\267A\"\n  \"^\\12GP\\243K\\223\\254\\222\\6_\\7\\27\\320\\241\\70\\4`\\7D\\24\\243\\10\\33a\\21\\207\\22\\246\\31\\242\\60\"\n  \"\\216\\6%L\\302$\\214\\206$b\\17\\267\\22\\252\\210[&-I]\\267$\\231\\0c\\14\\206\\22\\242\\32\\222\\60\"\n  \"m\\216\\207\\0d\\16\\267\\22\\252nZj\\253k\\222IK\\0e\\16\\207\\22\\246\\332*\\351p\\316\\201,\\233\\0\"\n  \"f\\14\\265\\20\\226\\223\\302h\\220\\302>\\1g\\20\\267\\262\\251Zj\\253k\\222IK\\234FC\\4h\\14\\267\\22\"\n  \"\\252\\210[&-I}\\15i\\10\\261\\24\\222P\\206Aj\\12\\343\\260\\221\\252F\\375i\\1k\\20\\266\\22\\246H\"\n  \"\\333\\222\\250\\222\\211I\\26\\325\\222\\60l\\7\\261\\24\\222x\\20m\\22\\213\\24\\276H\\246E\\63\\206b(\\206b(\"\n  \"\\206b\\1n\\13\\207\\22\\252H\\206DT}\\15o\\15\\207\\22\\246\\332*\\251k\\222e\\23\\0p\\20\\267\\262\\251\"\n  \"H&-I]\\267$\\231\\342\\62\\0q\\16\\267\\262\\251Zj\\253k\\222IK\\334\\0r\\12\\205\\22\\232H\\6\"\n  \"-\\354\\21s\\14\\206\\22\\242\\31\\222PvL\\206\\4t\\13\\245\\20\\232\\12\\243A\\12{\\25u\\12\\206\\24\\252\\10\"\n  \"\\375\\246,\\1v\\17\\207\\22\\246H\\255I\\26e\\225\\60I\\63\\0w\\30\\213\\22\\262\\10C\\61\\324\\222,\\211\\222\"\n  \"\\250\\222%Q\\222%Y\\32\\246\\21\\0x\\17\\207\\22\\246H\\223\\254\\222\\306i\\222U\\322\\0y\\22\\267\\262\\245H\"\n  \"\\325$\\213\\262J\\230\\244q\\32\\207*\\0z\\12\\206\\22\\242\\270\\206\\275\\16\\3{\\14\\343\\364\\241J\\242.Q\\26\"\n  \"u\\13|\\7\\1\\327\\241\\370!}\\15\\343\\364\\241\\310\\242nQ\\22u\\211\\0~\\11\\67\\260\\242\\21\\243\\242\\2\\200\"\n  \"\\22\\307\\20\\242\\333*q:h\\351\\240\\305u \\313\\26\\0\\0\\0\\0\\4\\377\\377N\\15&\\17\\321\\301\\207\\223\\341\"\n  \";\\222\\23r\\70'\\344\\260\\222cI\\224#Q\\246f\\241\\26\\246Q\\232\\23rBN\\310\\11\\71\\0N- \"\n  \"\\16\\323\\301\\316\\341\\34N\\223\\341k%\\255\\244\\225\\264\\62<$i\\35\\310\\341\\34\\316\\341\\34\\316\\341\\34N:,\"\n  \"\\17\\321\\301Gr(\\314\\61)\\7\\243\\234\\20&\\303w \\315\\221\\64\\7\\342\\34H\\302\\70\\223\\342\\60Js$\"\n  \"\\314\\241,\\7\\222,\\207\\62\\0N;\\42\\377\\360\\301\\316)\\71!\\314\\206\\207\\34\\311\\11\\71!'d\\351p\\320\"\n  \"\\241\\234\\220\\23rBNH\\223\\341\\3O\\21+\\17\\321\\301\\254Ca\\16\\205\\71\\222fa\\62\\34\\42\\65N\\302\"\n  \"\\61\\12w K\\312YR\\216Z\\223,\\63fa\\232#i\\216\\244)\\0OS,\\17\\321\\301\\13s(\\314\"\n  \"\\241\\60G\\322\\34I\\206C\\244%\\305$K\\312Qk\\324\\232d\\305$\\31\\224I\\254\\245\\71\\222\\346H\\232#\"\n  \"i\\14O\\134-\\17\\321\\301\\214r\\60\\312\\301(\\15\\263a\\320\\242$G\\244$\\7\\222R-\\322\\6\\65\\314\\241\"\n  \"\\60\\207\\302,\\15\\207\\261\\16\\205\\71\\24\\346P\\30\\3O`%\\16\\321\\301\\253CY\\16e\\71\\222\\15\\203\\224\\305\"\n  \"\\211\\24'\\215qcR\\254DY)\\222j\\245\\270c\\22\\247)\\0O\\335,\\377\\360\\301\\313\\11\\321\\60\\244Q\"\n  \"\\32fi\\230\\245\\231\\66\\14Q\\22\\347@\\62\\34\\244t\\16\\223j\\230T\\263\\250\\30eQ\\230\\204\\231\\24\\247\\0\"\n  \"O\\341+\\17\\321\\301\\314r,\\314\\322\\341\\240\\345\\204\\34\\11\\225\\341\\224\\344`\\224#i\\62\\34sB\\64\\14i\"\n  \"\\224\\226\\322RZ\\32\\206\\64J#\\0P<+\\17\\321\\301\\254Ca\\24\\17\\207\\60\\315\\221\\64\\12\\245a\\220\\222\"\n  \"(\\215J\\303\\220Fii\\30\\322(-\\15C\\32\\245\\245\\64\\35\\336r\\20P\\250\\63\\17\\321\\301Ks$\\315\"\n  \"\\21\\61\\12\\243d\\30\\262(KBYJ\\222!\\31\\6\\251-\\214\\222a\\310\\42%\\13\\243Z\\30%\\303\\30)\"\n  \"Y\\30\\325\\302t\\20\\323,\\2Q\\62\\66\\377\\360\\301\\213s \\11s \\312JY\\64$Q\\62(Q\\244\\3\"\n  \"I\\224$\\303A\\312\\221\\64\\31\\242A\\212\\265(\\31\\224,J\\242h\\220\\222\\250\\26%C\\64HIT\\13Q\"\n  \"e'\\17\\321\\301\\315)\\71%'\\344\\204\\34Nr\\64\\311\\321$\\7\\263\\34\\253Ci\\216\\244\\71\\220\\3i\\216\"\n  \"\\204\\71\\66\\344h\\2Qs)\\17\\321\\301\\313\\201\\34\\210u \\314\\241,\\312\\206\\207\\34\\311\\11\\71!M\\206\\357\"\n  \"@\\16'\\71\\232\\344`\\226C\\251\\35\\31t\\60\\1Q\\306,\\17\\321\\301\\7\\222\\70\\215b-*F\\303\\71\\313\"\n  \"\\201DKRe\\30\\304(\\213\\263J\\264\\15\\203\\326\\234\\225\\263R\\226\\15\\247,'\\344\\10\\0R\\6.\\17\\321\"\n  \"\\301Gr\\60\\312\\301,\\207\\302\\34Js \\7\\322\\34\\312\\242aH\\206\\64\\213r \\313\\261:\\24\\346P\\230\"\n  \"#i\\16dI\\16\\244\\61\\0R\\7+\\17\\321\\301\\313\\11\\71\\24f\\303\\240\\245Y\\230d\\305!\\312\\222!\\315\"\n  \"\\302\\64\\13\\323,\\214ja\\222\\25\\265\\260;\\222\\346@\\226\\304j\\6R =\\16\\321\\301\\207\\262dH\\6)\"\n  \"\\211\\222(K\\242$J\\232\\222(iJ\\242\\244)\\211\\222dxHJI\\224\\64%Q\\322\\224DIS\\22\"\n  \"%MI\\224%Q\\22eI\\224DI\\42%\\221\\224\\0R*(\\376\\362\\301I+\\303 &\\235*\\235*\"\n  \"\\235*\\235*\\235\\242\\341\\220DI\\247J\\247J\\247J\\327\\244S\\245\\226-\\241\\230\\0R\\240(\\377\\360\\301\\313\"\n  \"\\11\\71!\\207\\302(\\32\\36\\224,\\214jaT\\13\\243Z\\30\\325\\232\\262\\246\\254)k\\312\\242J\\64(aV\"\n  \"\\1SU\\42\\17\\321\\301\\313\\201\\34Hs(\\213\\302\\341-\\354q\\70\\210}\\34\\16b\\235\\220&\\303w '\"\n  \"\\344\\204\\34S\\213'\\377\\360\\301G\\303\\341-\\315\\221\\64G\\322\\34Is$\\315\\302d\\70di\\216\\244I\\234\"\n  \"Fb\\232\\225s \\16\\223hxS\\363)\\17\\321\\301\\316\\11\\71!N\\206\\257\\71!\\207sB\\16\\244\\303A\"\n  \"Kr \\213r \\312r \\316\\201\\70\\7\\342\\341\\234\\3\\21\\0T\\15'\\16\\321\\301\\316\\341\\34\\35\\206\\270\\250\"\n  \"\\204\\71T\\7uL\\307t \\71\\34\\302\\34Hs \\315\\201\\64\\7\\322\\341\\232\\3\\11\\0T\\16*\\17\\321\\301\"\n  \"\\7st\\10\\207!GrB\\216e\\303C\\224\\23r(\\214\\206[\\24\\207Q\\34FqV\\316\\312Q\\70\\14\"\n  \":\\20G\\0T&*\\17\\321\\301\\207\\223\\341;\\222\\303\\71\\254\\243I\\242#Q&j\\351\\220fQ\\66\\34\\322\"\n  \"\\34\\210s \\316\\201\\70\\7\\342\\341\\234\\3\\31\\0T/+\\17\\321\\301\\7rJ\\30\\16o\\71\\24\\346P\\230C\"\n  \"\\341p\\20sB\\16\\205\\303\\233\\216dI\\216dI\\216Du\\244\\66\\34\\322\\34I\\0TJ'\\17\\321\\301\\7\"\n  \"r\\254\\216\\65\\17\\207\\64\\313\\241\\60'\\244\\311\\360\\35\\214\\207C\\232\\3q\\16\\304\\71\\20\\347@<\\234s \\3\"\n  \"T}+\\17\\321\\301\\7rB\\16'\\71\\230\\345P\\252\\16\\337\\261pP\\206\\255\\222\\205Y\\222\\205Y\\222\\205Y\"\n  \"\\42\\205\\203\\322\\230%Q\\16\\346\\204\\30U$(\\16\\323\\301Gr$L\\7i\\220\\332JI\\26%Q\\64\\234\"\n  \"\\272D]\\242.Q\\227h\\370\\32Fa\\222cu$\\25\\345\\4U_-\\376\\362\\301Js$\\314\\242$J\"\n  \"\\206e\\30\\264(\\214\\32\\243$\\33\\66-\\214\\42%\\34\\223:\\20E\\303!\\314\\201\\64\\7\\322\\341\\232\\3\\21\\0\"\n  \"U\\256%\\377\\360\\301\\32\\224A\\314\\222,\\314\\222,\\34\\224A'\\17\\347\\254<\\234\\263\\362p\\316\\352X\\232\\14\"\n  \"\\337\\201\\234\\220\\3Vh\\63\\17\\321\\301\\32\\224A\\314\\222,\\314\\222,\\314\\222,\\34\\224A\\207\\352`\\226$\\303\"\n  \"\\347$\\307\\314: \\15C\\62\\14Q\\226da\\226da\\226d\\341\\240\\14\\22\\0V\\336%\\356\\362\\301G\\223\"\n  \"\\341;\\230\\344@\\226d\\303\\224d-YK\\326\\222\\265d\\203\\226d-\\71\\230\\14\\17I\\16&\\0W\\213-\"\n  \"\\377\\360\\301\\7\\322h\\30\\304R\\26\\205Q\\26\\205Q\\26%\\303%\\12\\243,\\12\\243,\\12\\243\\70\\313\\264$J\"\n  \"\\303lx\\310\\221\\234\\220&\\303\\7X\\323\\61\\377\\360\\301\\312\\261lx\\210\\222(K\\223!\\23\\223(K\\262d\"\n  \"\\70HI\\26\\245\\311 \\245I\\26\\211\\311\\240DR\\222\\211Q\\32\\205\\321p\\213\\303$\\32\\36Y\\15,\\17\\321\"\n  \"\\301\\313\\221t\\70h\\71!\\31\\6\\61\\212\\263l\\30t \\316\\201\\203\\216\\344\\360\\60\\350\\200\\230\\3Q\\35\\10u\"\n  \" \\214r,Tw`Y\\32$\\15\\323\\301\\315\\321\\34\\34\\206\\264*\\246Q\\242cI\\216H\\351\\66\\14iQ\"\n  \"\\15\\243,\\14w,\\207v`\\307\\0Y'$\\377\\360\\301\\7rBN\\310\\11\\71!M\\206\\357@\\16'\\71\"\n  \"\\232\\344h\\224cu,\\314\\221\\270\\216,:\\226\\0Y\\64(\\17\\321\\301GrB\\216\\325A%G\\262$\\207\"\n  \"\\264\\34\\253\\23\\302d\\370\\216\\344pNHt,\\314\\221\\70\\325\\1I\\307\\22\\0[W#\\16\\321\\301\\316\\11\\71\"\n  \"\\360!\\311A\\35\\14\\207AGs\\64Gs\\340C\\16\\344p\\16\\347p\\16&\\71\\232\\3[X(\\17\\321\\301\"\n  \"\\316\\11q\\62|\\315\\341\\234\\220\\14C\\232\\3qY\\315\\242dx\\210\\322\\34Is$\\315\\221\\64G\\262$G\"\n  \"\\302\\30[\\232(\\17\\321\\301\\316)\\71\\62<(\\71\\252\\243\\71\\232\\16\\7\\35\\312\\11\\71V\\312\\201l\\220\\263\\34\"\n  \"\\253CI\\224#\\331\\16\\304\\303 \\134O(\\17\\321\\301G\\303\\341-\\207\\302\\34\\12\\207\\203\\230\\225\\303$\\12\\223\"\n  \"\\341\\220\\65g\\245lx\\210\\262rV\\15\\263\\260\\35IC\\0]\\345\\35\\337\\20\\302G\\263\\341!GrBN\"\n  \"\\310\\11\\71!'\\344\\204\\234\\220\\23rB\\232\\14\\37]\\346\\42\\377\\360\\301\\316\\11\\71!\\215\\206\\7\\71'\\344\\204\"\n  \"\\34\\256\\3\\257a\\16\\205\\71\\222\\346@\\134\\7\\302hx\\20]\\362#\\375\\362\\301\\307\\242\\341\\35\\314\\321,G\\262\"\n  \"\\34\\311\\206C\\226#Y\\216\\346h\\216\\346X\\222cI\\216E\\303A^U)\\17\\321\\301\\315\\242lx\\210\\263\"\n  \"$\\36\\16i\\16\\304\\303\\71\\7\\342\\341\\216\\344@\\62|k\\35\\276d\\225\\60K\\312Y\\224\\203\\71\\0^\\246*\"\n  \"\\17\\321\\301\\7rJ\\230\\15\\17QV\\316*\\341\\360\\326\\234\\15rNH\\206A\\315\\312a\\222\\3i\\16\\204\\212\"\n  \"\\230\\251C\\244C\\11\\0^\\372-\\17\\321\\301\\207rB:(\\303\\20\\207Q\\232\\14\\207,\\215\\302e\\30\\342\\60\"\n  \"\\315\\222a\\210\\252q\\222\\306I\\62\\334\\342\\34\\210+b\\32\\16\\207\\0_\\214-\\17\\321\\301\\254Ca\\216\\204Y\"\n  \"X\\13\\243d\\320\\221\\60G\\302,T\\206S\\222\\345@\\224\\15k\\224Vjq\\230\\344@\\232#\\231\\42'\\352\"\n  \"\\0_\\251,\\377\\360\\301\\223\\322\\60\\33\\6)\\313\\241,\\31\\206$\\222\\322\\60\\33\\206,L#q\\30\\222j\\216\"\n  \"\\204\\303\\220eb\\251\\65\\226CI\\214d\\1`b\\61\\17\\321\\301\\13s(\\314\\241\\260e\\70$\\211\\226\\3I\"\n  \"S\\232dQ\\30eQ\\61J*b\\24\\315Q\\226\\3I\\230\\3I\\226\\304b\\22\\207\\331\\26\\251\\11\\0`o\"\n  \"+\\17\\321\\301\\316\\341\\64\\36\\16i\\16\\304\\71\\20\\17\\347\\34\\210\\207s\\16\\304\\71\\20\\17w(\\207\\222L\\214\\222\"\n  \"\\60\\212\\244\\34\\210\\302a\\320\\0bK&\\17\\321\\301\\7sp\\320\\206!'\\344\\204,\\35\\16:\\224\\23rB\"\n  \"\\232\\14\\337\\201\\234\\220\\23rB\\216&\\71\\234#\\0b\\351/\\17\\321\\301\\313\\11\\321\\60\\244Y\\71L\\302a\\313\"\n  \"\\221\\60\\311\\201\\244\\26+Q\\64)\\311\\240$J\\232#i\\224&\\303\\61\\315\\221\\64N\\322\\34\\210S\\0c\\1\"\n  \".\\17\\321\\301Ks$\\315\\221\\64\\211\\243a\\210\\206-G\\322(M\\206\\243\\234\\352@\\222(\\311p\\310\\242\\60\"\n  \"\\316\\312Y\\71\\7\\302$M\\322\\34\\10\\1cb-\\17\\321\\301\\13s(\\314\\241l\\220\\243,\\34\\266(\\215\\206\"\n  \"A\\214Z\\207\\250(\\65)Q\\353\\360\\226\\346H\\230\\344@VL\\242tJt \\1c\\247-\\17\\321\\301K\"\n  \"s$\\316\\201h\\270E\\71p\\310\\222b-M\\252\\241\\216\\352H\\244D\\303 \\306\\71\\20\\347@\\234\\3qT\"\n  \"I\\206C\\224\\243\\0c\\320\\60\\17\\321\\301\\313\\221\\64\\33\\206\\60\\13\\323,\\214\\206eX\\263\\60M\\212\\251\\64\\214\"\n  \":\\250$\\303!\\213s \\213\\222\\64\\213\\206\\60\\213\\322$J\\312Q\\66\\14c\\333-\\377\\360\\301\\13\\243\\70\\34\"\n  \"\\324\\254\\66\\14Y\\16D\\303\\220FIk\\242\\264*\\225i\\210\\224(K\\242\\326d\\70di)L\\304-\\234\"\n  \"\\42\\71\\1d\\307,\\377\\360\\301\\213\\206[T\\211\\262\\250\\22\\15\\37\\262\\70\\7\\262a\\10\\223\\60\\7\\224\\341!\\13\"\n  \"\\263$\\214\\342h\\270\\305a\\24\\15\\227\\271\\16\\204\\0ep/\\17\\321\\301,G\\225\\34HJ\\71\\224\\205\\311\\360\"\n  \"M\\12+RVJji\\230E\\303\\20%i\\26%\\241V\\7\\222,\\311\\201\\254\\250\\24\\7\\61N\\0ex\"\n  \"-\\377\\360\\301,\\17C\\22G\\225t\\70dQ\\313\\260\\14\\247\\70\\214\\262aH\\242,\\252D\\331\\60$Q\\32\"\n  \"'\\321pJ\\263\\212\\270e\\303\\264\\6e\\207(\\17\\321\\301\\316)\\71!M\\206o\\71\\220\\3q\\16\\244\\71\\24\"\n  \"\\346P\\226\\203I\\16\\347p\\222\\203\\231\\216\\304\\251\\216\\14:\\230\\0e\\260.\\17\\321\\301\\313)\\71\\360\\240\\254Y\"\n  \"\\224#Q\\35\\251\\15\\17J\\24\\207Q\\34F\\321\\60(Q\\230hQ\\230\\264\\225\\222Z\\224Ea\\245ZG\\42\"\n  \"\\0e\\366(\\16\\323\\301\\7\\343\\322\\260FY\\34e\\303A\\213\\243,\\216\\6)\\213\\262R\\255T\\213\\243,\\216\"\n  \"\\6\\71\\312J\\71\\230\\344h\\6f/-\\17\\321\\301\\34\\206\\34Is$\\315\\221a\\310\\221\\64G\\322\\34\\31\\206\"\n  \"\\234\\226\\14\\337\\201\\34\\214\\352H\\64\\350@\\224cI\\35\\312t$\\36\\206\\0fB+\\376\\362\\301\\207r \\15\"\n  \"\\7e\\30\\222(\\15\\243\\64\\214\\222\\341!\\307\\242\\34\\210*\\303!\\312\\201\\250\\222FC\\24F-Q\\16\\356h\"\n  \"\\6f\\364#\\17\\321\\301\\207\\223\\341;\\20\\206\\303[\\330\\343p\\20\\373\\70\\34\\304$\\12s \\311\\341\\34Nt\"\n  \"H\\334vhg\\0*\\17\\321\\301\\33\\316\\71\\20\\17\\347\\34\\210\\207;)\\31>e\\71\\66\\274U\\302lP\\262\"\n  \"\\60\\213\\222t\\320\\302-Jt\\244\\66\\253\\11\\0g,(\\17\\321\\301\\7rBN\\310\\11a\\66<\\304I\\35\"\n  \"K\\352XR\\207\\332\\221\\250\\16d\\325d\\30\\222A\\255#\\71!'\\344\\0h!+\\17\\321\\301Ks$\\316\"\n  \"\\201\\34\\12\\243\\341;\\32f\\241\\226JK-\\351\\224U\\322$\\213\\322$\\256\\3i\\22\\207Y\\32\\211\\333\\16$\"\n  \"\\0ke*\\17\\321\\301\\7r\\60\\312\\301(\\313\\201h\\230\\243\\34\\214\\322d\\370\\16\\344`\\224\\345\\200\\222\\251Y\"\n  \"\\24\\207Q\\216\\352\\240\\16\\352\\330\\16\\2mK,\\376\\320\\301\\311\\201,\\212\\206\\251-I\\304\\244\\213\\224t\\252t\"\n  \"T\\272%=UZ\\206(\\351\\24\\246Q\\226\\204Q\\255\\224\\204I)\\207\\22\\0n)/\\17\\321\\301G\\263p\"\n  \"\\30\\64)-\\245Q:\\14\\231\\226\\206Y\\32'\\303\\220\\346p\\64\\134\\246J\\224E\\225(\\213*Q\\26U\\242\"\n  \",\\31\\16R\\216\\2n,\\62\\377\\360\\301\\311\\212Q\\64lQ-L\\263$\\322\\206%J\\332\\222(iK\\242\"\n  \"\\322\\240DmI\\264U\\242$\\33\\224(\\311*\\321\\230\\244[eH\\242\\60K\\0n\\226(\\376\\362\\301\\11\\223\"\n  \"\\34\\310\\242J\\224\\14\\227\\266\\70\\31nJ\\26j\\303 e\\325l\\270d\\71%L\\206\\7\\35\\310\\341\\34\\216\\1\"\n  \"n\\253\\63\\377\\360\\301\\11\\323\\60\\33\\6\\255\\32'i\\224%\\303\\220%Q\\232%\\321\\60\\204Y\\32F\\71\\220h\"\n  \"\\303!\\311\\242$\\252EI\\224hQ\\22%Z\\224D\\245\\341 p\\272)\\376\\362\\301\\312t\\250\\216%Y\\70\"\n  \"\\34t$\\313\\241,G\\206A\\256\\346@\\230\\14\\207$\\7\\62))\\325\\222(\\211:\\346\\330\\2p\\331\\60\\17\"\n  \"\\321\\301\\13s(\\314\\241p\\30\\223j\\224HZ%\\252\\204I\\34Fi\\22g\\332\\226\\310a\\66\\14a\\226f\"\n  \"I\\224fQ\\222F\\351\\60$q\\232\\0p\\355*\\17\\321\\301\\254Ca\\16\\205Q\\66<\\244a\\24'Qu\"\n  \"\\222\\62%\\214\\342,)g\\225(\\211\\302$\\213\\342\\234\\26e\\275\\215Y\\30q\\261)\\376\\362\\301Ks M\"\n  \"\\7-I\\263a\\31\\206(\\11\\223\\60\\211\\224\\304\\222V\\262AJ\\224\\254\\70\\234sJ\\224\\225\\262\\232\\230\\25r\"\n  \"H\\61\\17\\321\\301\\314\\201,\\212\\247\\322\\220Fu$\\252#\\203\\62\\14QZJ\\223(\\33\\242$\\312\\242J\\61\"\n  \"*\\211Q\\222\\245Q\\22%a$eC\\26\\245u\\14u(%\\16\\321\\301G\\263\\341)\\254\\205\\265\\260\\66\\34\"\n  \"\\264\\260\\26\\326\\302\\332p\\320\\302ZX\\13Ki\\30\\245QR\\307\\42\\0u\\65!\\375\\362\\301\\315\\321\\34\\15\\243\"\n  \"\\341%,\\205\\245\\341 \\205\\245\\260\\64\\34\\244\\260\\16\\344h\\234\\306\\361\\60\\4v\\204\\60\\16\\323\\301Js \\215\"\n  \"\\263(K\\206!\\31\\206\\60\\11\\223PM\\302\\70\\11\\223\\60\\31&)\\11\\263(\\11\\343$\\214\\223\\60N\\206\\71\"\n  \"\\11\\263$G\\63\\0w \\64\\16\\323\\301\\7\\243!\\31\\6%J\\322\\250\\222F\\225\\64\\32\\222a\\210*Q\\32\"\n  \"%Q\\226D\\311\\360\\220Di\\224da\\224da\\224\\204\\331\\220\\224\\42)\\21\\223\\64\\26xn\\62\\17\\321\\301\"\n  \"\\207r\\254:\\14\\321\\220\\206Q\\234E\\265l\\70U\\242\\322\\240D\\225R\\62\\14Y\\224D\\265(\\211jQ\\62\"\n  \"\\14Y\\224D\\265!\\211jMq\\254\\0x\\272\\60\\377\\360\\301\\307r(\\211\\262\\341CV\\311\\302\\64I\\323a\"\n  \"\\210\\206$\\13\\245\\255\\22%\\303 U\\262\\64J\\262\\64J\\206A\\32\\222,\\215\\222,\\307\\206Ay\\201,\\17\"\n  \"\\321\\301Ls$M\\262a\\31FqM\\244\\244\\26%R%K\\263\\234\\66\\34t\\332\\360\\35\\310\\301\\250\\16d\"\n  \"\\231\\30%a\\216\\344\\10\\0y\\322\\60\\17\\321\\301\\15sdK\\207\\64G\\322\\34\\311\\222\\322\\60$%\\61K\\262\"\n  \"l\\211r@\\311\\242,I\\243,I\\223,\\212\\263j\\216\\204\\71\\224\\345X\\242\\3y\\360,\\17\\321\\301\\315r\"\n  \"h\\212\\207,\\307\\352X\\64|N+\\351\\230\\3J\\307$K\\242,\\211JJ\\324\\246%Y\\216\\244\\71\\222%\"\n  \"\\71\\22\\246\\0z\\15\\62\\17\\321\\301Ls`\\211*C\\230Da\\245\\32G\\311\\260\\14\\203V\\315\\246\\64S\\222\"\n  \"a\\210\\222,\\215\\222,M\\242l\\30\\302,\\15\\263\\64\\314*a\\26F\\0z\\61\\60\\377\\360\\301M\\17C\\70\"\n  \"dI\\246\\205I\\24&QR\\32\\206,\\7\\262a\\10\\245\\66%\\31\\206(\\311\\242J\\224E\\305d\\70d\\325\"\n  \"\\60\\313\\306,\\214\\0{I(\\17\\321\\301Ks\\244\\26\\205\\203\\62L\\335\\241$\\313\\261\\34\\32\\16:\\224\\3\\277\"\n  \"C\\71!I\\207\\203\\34\\346X\\35Mr\\70\\6{\\200\\65\\17\\321\\301\\213j\\341\\240\\14S\\222%i\\226d\\245\"\n  \"\\34\\11\\223d\\30\\264\\34\\12\\243A\\12\\243,\\12\\243,\\12\\243A\\12\\243,\\12\\243,\\12\\243A\\12s \\11\"\n  \"s$\\3|{(\\17\\321\\301\\7r\\254\\35\\210\\352`mx\\310\\221\\34M\\352PI\\316\\352X\\232\\14\\237\\223\"\n  \"\\34\\314r(\\315\\201\\34\\230t(\\2~A-\\17\\321\\301\\312\\312\\303\\324\\16\\34\\222A\\321*\\265$\\32Ni\"\n  \"RK\\246A\\321r \\313\\201C\\216\\352\\240\\230\\16\\7\\71\\252\\3R&fi\\4\\177n'\\377\\360\\301\\32\\16\"\n  \"b\\224E\\341p\\320\\241\\34\\31\\36r$\\307\\206s\\16\\304\\303\\71\\7\\342\\341\\234\\3\\361p\\316\\201$\\31>\\200\"\n  \"\\375\\60\\17\\321\\301\\13s(\\314\\302\\250\\244\\225\\222p\\30\\22\\35L\\302h\\220\\302(\\313\\6i\\320\\261R\\326\\24\"\n  \"i\\203\\224\\244Y$gQ\\232\\64\\245I\\24\\16\\3\\203\\334'\\17\\321\\301\\315r\\254e\\370\\232\\345\\224q\\30t\"\n  \"$\\12s \\252\\203i\\62|\\336\\301\\244\\16\\225\\344,\\134\\304\\64Gr\\0\\207\\2\\61\\17\\321\\301\\13s(\\314\"\n  \"\\241p\\30\\223D\\313\\206)\\11\\223b\\232\\224\\224!\\251L-\\245A\\33\\304\\64\\311\\206!L\\302\\34X\\206!\"\n  \"\\231\\302\\64GrB\\10\\212-*\\377\\360\\301J\\243\\70\\34\\324\\60\\312\\206!\\211r\\60\\312\\261p\\31v\\312\\60\"\n  \"D\\203\\224\\345Xm\\220\\262.a\\26\\246\\203\\244h\\331*\\212\\215/\\377\\360\\301\\312\\261\\60\\32nq\\224\\14C\"\n  \"R\\312\\241$\\312\\221\\250\\64h\\311\\16e\\331\\240D\\71%\\34\\264\\244\\224%\\305$KJI\\62L\\265\\342\\4\"\n  \"\\212\\244-\\377\\360\\301\\212\\7\\61\\315\\302,\\311\\222a\\251\\345H\\62\\350H-\\32\\242\\234p\\210\\206\\64\\312\\301(\"\n  \"\\32\\222\\341\\22\\245\\245\\60\\11\\207\\254)Q\\5\\212\\313/\\377\\360\\301\\311\\221\\70\\33N\\71\\20\\16\\313\\60\\344`\\216\"\n  \"\\15\\337I\\303\\220\\14K\\232#\\303\\220\\14K\\232\\204\\311\\60$a\\222&\\303\\222-a\\22F\\0\\213f&\\17\"\n  \"\\321\\301K\\262x\\30\\222A\\14\\245p\\230\\222,i\\213\\227D\\231\\325d\\370N\\34\\356\\14\\357\\14\\317\\71\\20\\17\"\n  \"\\67\\0\\213\\244+\\17\\321\\301\\207\\342\\34\\310\\1\\65G\\322\\234\\220\\23\\322!Lr Lr Lr +g\"\n  \"\\345\\244\\26+i)\\315\\201\\34\\20s$\\1\\213\\276,\\17\\321\\301\\7\\6\\65\\314\\342\\254\\234\\325\\261:\\224\\16C\"\n  \"\\222\\243\\321\\60\\244Y\\230f\\345\\60\\212\\303$\\7\\222,G\\264D\\216\\304Q\\7\\22\\0\\213\\357*\\17\\321\\301G\"\n  \"\\263p\\30\\64)-\\245\\71\\62\\14\\71m\\32nq\\16\\304Ye\\70Hq\\16\\244I\\234dI\\254U\\263t\"\n  \"\\315\\201\\4\\213\\367/\\17\\321\\301\\207\\342\\34\\310\\201h\\270\\305\\71\\70\\14\\321\\234\\3\\311p\\220rB\\66\\14a\\226\"\n  \"\\206\\331\\60\\204Y\\32&\\311\\60\\204R\\32f\\225\\34\\11\\63\\0\\217\\70/\\377\\360\\301\\213s M\\262aH\\262\"\n  \"\\64K\\225a\\31\\224\\356\\330\\240\\14Y\\322)\\251\\14\\312\\220\\364)\\251\\225\\222dx\\251\\225\\262\\246d\\253H\\11\"\n  \"\\0\\217\\223\\66\\17\\321\\301\\212s M\\342$K\\302a\\311\\322,]\\262dP\\242$\\7\\243h\\310\\222A\\211\"\n  \"\\222b\\64$\\265%J*J\\64$\\305\\250R\\214jaT\\13\\243DR\\0\\217\\276*\\377\\360\\301Gr \"\n  \"\\316\\221\\64G\\322\\234\\220\\305\\303!Ys$\\314\\241\\60\\311\\201\\254\\234\\205i\\224\\212I\\16dI\\16m\\303!\"\n  \"\\1\\217\\324,\\17\\321\\301G\\263\\34\\332\\244A\\7\\242\\234\\220\\23\\222A\\32\\242\\264\\224DqT\\211\\243,\\7\\242\"\n  \"J\\234D\\231\\230T\\263$\\7\\263\\234\\62\\34\\217\\333%\\377\\360\\301\\316\\322\\60\\213\\263r\\62\\34r \\313\\261\\342\"\n  \"V\\316\\312\\311p\\310\\232\\263rV\\216\\302\\64\\211\\303l\\70\\10\\220\\11/\\17\\321\\301\\207\\342\\60\\312\\1\\251\\65\\32\"\n  \"\\6\\35\\210r\\254eH\\206C\\26&\\71\\20&\\71\\20&\\71\\220EYSV\\12\\207(\\321\\261: \\17\\203\"\n  \"\\2\\220\\62.\\377\\360\\301\\7\\222\\70\\215b)\\213\\302h\\270j\\71R\\313\\201h\\30\\224A\\311r \\32\\6\\61\"\n  \"\\312r \\312r \\32NR\\16\\325\\261p\\70\\4\\220T+\\377\\360\\301\\207\\342\\34\\310\\1i\\30\\304\\64\\307\\206\"\n  \"C\\16dq\\230D\\311\\360-\\315\\221h\\30\\304\\64G\\222\\341\\20\\251\\251\\24\\246\\341p\\10\\220x/\\377\\360\\301\"\n  \"\\35\\222!\\312\\242$\\312\\224!\\31\\302$\\314\\322L\\213\\207d\\310\\302(\\33\\224a\\20Kq\\62\\34\\262\\234\\220\"\n  \"I\\242\\42\\17Q\\216\\205\\303!\\221\\222\\64\\17\\321\\301\\315\\201d\\30\\222a\\210\\222,\\314\\222lX\\206!\\11\\223\"\n  \".\\303\\322-L\\222\\245(&\\303\\222Ja\\232\\205\\303\\220\\14K\\232\\205i\\26%\\303\\207\\64G\\0\\221\\315#\"\n  \"\\377\\360\\301\\307\\306a\\320\\321\\312\\360\\35\\310\\342\\341\\220f\\345\\341\\234\\225\\207;\\226C\\303A\\207rB\\232\\14\\37\"\n  \"\\221\\317%\\17\\321\\301\\7\\343\\341\\220\\346@<\\234s I\\206\\357\\304\\341\\234\\225\\207sV\\36\\356X\\216\\15w\"\n  \",G\\206\\207\\4\\223/\\61\\377\\360\\301K\\243T\\214\\322$\\213\\302l\\270\\344@\\24\\15[\\224f\\303\\240\\345\\340\"\n  \"\\60$\\303\\22%Q\\30%Z\\30%\\341\\60\\16I\\230\\14\\341\\60\\305a\\2\\224\\30-\\377\\360\\301\\312\\201X\\32\"\n  \"NI\\326K\\226\\16\\227AG\\263a\\10\\263\\250\\62,\\303\\220DY\\324R\\31\\206(Qs \\33\\206d\\30\"\n  \"\\323p\\70\\224\\65\\61\\377\\360\\301\\13\\243\\70\\214TeHjQc\\70|\\215\\243!\\211\\243J\\64\\34\\224HJ\"\n  \"\\322$J\\224!)%a\\244d\\303\\20%\\203\\30%J\\70h\\1\\224\\237/\\17\\321\\301\\213s \\316\\201\\70\"\n  \"\\7\\306(\\13\\207A\\12\\243\\322\\240D\\225(\\213\\212YT\\31\\226a\\10\\263\\250\\30\\347@\\22\\346\\200\\232\\3q\"\n  \"N\\10\\1\\224\\301/\\17\\321\\301Ks$Kr$K\\312\\313\\60Vr \\213\\342A\\213\\232\\206AL\\343A\"\n  \"\\313\\221\\60\\311\\201\\60\\311\\201\\244\\26KY\\34\\245k\\16$\\0\\225\\31\\60\\17\\321\\301\\13\\263\\64\\314\\302!\\312\\302\"\n  \"p\\30\\242\\70\\313\\6)\\213J\\303-'d\\303\\220\\14K\\32fi\\230\\15C\\230\\245aR\\15\\245a\\10\\263\"\n  \"\\64\\1\\225\\211+\\16\\323\\301\\70\\15C\\30\\205\\303\\20\\15C\\30\\205\\303\\20\\15C\\30\\205r*\\247\\312pH\\344\"\n  \"\\324MI\\25-\\25\\223T\\15\\23\\35L\\0\\225\\223+\\376\\362\\301\\70\\15C\\30\\205\\303\\20\\15C\\30\\205\\303\\20\"\n  \"\\15C\\30\\205:\\252\\15\\233\\26f\\332\\260ia\\246\\15\\233\\26J:\\66\\344`\\2\\225\\276/\\376\\362\\301\\70\\15\"\n  \"C\\30\\205\\303\\20\\15C\\30\\205\\303\\20\\15C\\234dr\\24)\\303!\\221Si\\220\\42\\251\\242ICR\\222\\23\"\n  \"I\\31\\304!\\7\\23\\0\\225\\334\\62\\376\\362\\301\\70\\15C\\30\\205\\303\\20\\15C\\30\\205\\303\\20\\15C\\24\\206J\\224\"\n  \"D\\221\\62mR\\22%\\221\\62$\\203\\42F\\241\\224DI$\\235\\304(\\32\\222\\255\\2\\225\\355.\\16\\323\\301\\311\"\n  \"\\261L\\31n\\71R\\16\\223\\70\\211\\222d\\270\\224\\303$\\25\\223\\60\\11\\223,\\12\\223(\\13\\223b%\\16\\223\\60\"\n  \"\\11\\223\\64K\\352X\\4\\225\\364\\63\\15\\323\\301\\311\\241L\\31\\6-\\7\\222\\34K\\242aJ\\242\\60J\\242\\60J\"\n  \"\\242\\60J\\242aJ\\242\\60J\\242\\60J\\242\\60J\\242aJ\\242\\60Jr\\244\\35\\212\\0\\226\\10\\63\\16\\323\\301\"\n  \"\\311\\261\\312p\\220\\223(\\211\\243$\\31\\36\\222\\70L\\222!\\11\\223R\\22%M\\225N\\221\\224$C\\224%\\71\"\n  \"\\220T\\206%Q\\252YR\\214\\223\\34S\\0\\226d/\\16\\323\\301G\\322!L\\243,\\11\\223\\60\\11\\223\\254\\246\"\n  \"\\245CR\\31\\224R\\230Fa\\222E\\303!Q\\302\\64\\311\\222Z\\30EJ\\326\\222&i\\34\\3\\226\\373(\\377\"\n  \"\\360\\301\\33\\16Y\\32'\\303\\347\\64\\33\\222d\\310\\241\\34\\32\\222d\\310\\251\\303Al\\34\\16b\\343pPr \"\n  \"\\316\\221a\\10\\227^&\\17\\321\\301\\315r\\254\\216\\265\\14\\333\\260f\\71V\\307J\\331\\240\\15r\\226cu\\254\\216\"\n  \"\\265\\14\\333\\260f\\71V\\307\\252\\0\\230-.\\377\\360\\301\\315\\201d\\370\\216\\245Y\\64L\\303\\22FY\\24FY\"\n  \"\\64L\\203\\24FY\\64\\314Q\\30\\325\\302,\\311\\206-Y\\302dH\\23-\\25\\5\\230^\\60\\376\\362\\301\\210\\252\"\n  \"QR\\31\\206\\244\\61\\16\\7e\\30\\222,\\333JIiP\\242J\\26&\\321 FI\\226\\14C\\222\\205\\341\\240\"\n  \"%Y)\\253Da\\242\\11\\230y*\\17\\321\\301\\207\\323d\\370\\230\\3i\\26f\\303\\240U\\303,*fQ\\61\"\n  \"\\213\\212YT\\134\\242\\312\\220E\\255Q\\35Kt,\\314\\1\\71\\232\\330(\\17\\321\\301\\316)\\71\\360;u\\30r\"\n  \"$\\315\\221a\\310\\311\\303C\\224\\203Q\\64\\14Qk\\324\\32\\225\\206!\\252\\203Q\\16-\\0\\234\\364/\\376\\362\\301\"\n  \"G\\304(\\211J\\303C\\22%iT\\31\\206\\250\\222F\\225a\\210*\\71\\22%\\303C\\222#Q\\62\\34r\\64\"\n  \"L\\232\\302(i\\253$\\12\\0\\236#*\\16\\323\\301Gr$+\\15\\312\\60$Q\\61j\\211:F]\\242\\266\"\n  \"R\\65\\211\\242\\341\\35)\\245Q:\\14I\\16\\347`\\222\\243\\21\\0\\236\\330.\\17\\321\\301\\7\\242t\\30\\24\\61j\"\n  \"\\311\\224DJ\\223%*\\15\\17b\\232\\16C\\224#i\\216\\14Q:\\244\\71\\224\\64&=&\\245,\\252\\205s\"\n  \"\\5\\377\\32\\12\\202^\\302\\30rd\\10\\0\";\n"
  },
  {
    "path": "SolderingPen_ESP32S2/SolderingPen_ESP32S2.ino",
    "content": "//\n#include \"config.h\"\n\n//\n#include <Button2.h>\n#include <QC3Control.h>\n\n//\n#include \"FirmwareMSC.h\"\n#include \"Languages.h\"\n#include \"USB.h\"\n#include \"UtilsEEPROM.h\"\n\nQC3Control QC(14, 13);\n// QC.set12V();\n\n#include <U8g2lib.h>  // https://github.com/olikraus/u8g2\n// font\n#include \"PTS200_16.h\"\n\n\n// #include<analogWrite.h>\n#include <ESP32AnalogRead.h>  //Click here to get the library: http://librarymanager/All#ESP32AnalogRead\n\n#include \"esp_adc_cal.h\"\n\n#ifdef U8X8_HAVE_HW_SPI\n#include <SPI.h>\n#endif\n#ifdef U8X8_HAVE_HW_I2C\n#include <Wire.h>\n#endif\n\n#include <PID_v1.h>  // https://github.com/wagiminator/ATmega-Soldering-Station/blob/master/software/libraries/Arduino-PID-Library.zip\n// (old cpp version of\n// https://github.com/mblythe86/C-PID-Library/tree/master/PID_v1)\n#include <EEPROM.h>  // 用于将用户设置存储到EEPROM\n\n// 选择加速度计芯片\n// #define MPU\n#define LIS\n\n/*#if defined(MPU)\n  #include <MPU6050_tockn.h> //https://github.com/tockn/MPU6050_tockn\n  MPU6050 mpu6050(Wire);*/\n\n// #if defined(LIS)\n#include \"SparkFun_LIS2DH12.h\"  //Click here to get the library: http://librarymanager/All#SparkFun_LIS2DH12\nSPARKFUN_LIS2DH12 accel;  // Create instance\n\n/*#else\n  #error Wrong SENSOR type!\n  #endif*/\n\nint16_t gx = 0, gy = 0, gz = 0;\nuint16_t accels[32][3];\nuint8_t accelIndex = 0;\n#define ACCEL_SAMPLES 32\n\n// 定义积极和保守的PID调整参数\ndouble aggKp = 11, aggKi = 0.5, aggKd = 1;\ndouble consKp = 11, consKi = 3, consKd = 5;\n\n// 用户可以更改并存储在EEPROM中的默认值\nuint16_t DefaultTemp = TEMP_DEFAULT;\nuint16_t SleepTemp = TEMP_SLEEP;\nuint8_t BoostTemp = TEMP_BOOST;\nuint16_t time2sleep = TIME2SLEEP;\nuint8_t time2off = TIME2OFF;\nuint8_t timeOfBoost = TIMEOFBOOST;\nuint8_t MainScrType = MAINSCREEN;\nbool PIDenable = PID_ENABLE;\nbool beepEnable = BEEP_ENABLE;\nvolatile uint8_t VoltageValue = VOLTAGE_VALUE;\nbool QCEnable = QC_ENABLE;\nuint8_t WAKEUPthreshold = WAKEUP_THRESHOLD;\nbool restore_default_config = false;\n\n// T12的默认值\nuint16_t CalTemp[TIPMAX][4] = {TEMP200, TEMP280, TEMP360, TEMPCHP};\nchar TipName[TIPMAX][TIPNAMELENGTH] = {TIPNAME};\nuint8_t CurrentTip = 0;\nuint8_t NumberOfTips = 1;\n\n// Variables for pin change interrupt 引脚更改中断的变量\nvolatile uint8_t a0, b0, c0, d0;\nvolatile bool ab0;\nvolatile int count, countMin, countMax, countStep;\nvolatile bool handleMoved;\n\n// Variables for temperature control 温度控制变量\nuint16_t SetTemp, ShowTemp, gap, Step;\ndouble Input, Output, Setpoint, RawTemp, CurrentTemp, ChipTemp;\n\n// Variables for voltage readings 电压读数变量\nuint16_t Vcc, Vin;\n\n// State variables 状态变量\nbool inLockMode = true;\nbool inSleepMode = false;\nbool inOffMode = false;\nbool inBoostMode = false;\nbool inCalibMode = false;\nbool isWorky = true;\nbool beepIfWorky = true;\nbool TipIsPresent = true;\nbool OledClear;\n\n// Timing variables 时间变量\nuint32_t sleepmillis;\nuint32_t boostmillis;\nuint32_t buttonmillis;\nuint32_t goneMinutes;\nuint32_t goneSeconds;\nuint8_t SensorCounter = 0;\n\n// Specify variable pointers and initial PID tuning parameters\n// 指定变量指针和初始PID调优参数\nPID ctrl(&Input, &Output, &Setpoint, aggKp, aggKi, aggKd, REVERSE);\n\n// Setup u8g object depending on OLED controller\n// 根据OLED控制器设置u8g对象\n#if defined(SSD1306)\nU8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE,\n                                         /* clock=*/22, /* data=*/21);\n#elif defined(SH1107)\nU8G2_SH1107_64X128_F_HW_I2C u8g2(U8G2_R1, 7);\n#else\n#error Wrong OLED controller type!\n#endif\n\n// Buffer for drawUTF8\nchar F_Buffer[20];\n\nfloat lastSENSORTmp = 0;\nfloat newSENSORTmp = 0;\nuint8_t SENSORTmpTime = 0;\n\n// ADC Calibrate\nuint16_t vref_adc0, vref_adc1;\nESP32AnalogRead adc_sensor;\nESP32AnalogRead adc_vin;\n\n// Language\nuint8_t language = 0;\n\n// Hand Side\nuint8_t hand_side = 0;\n\n// MSC Firmware\nFirmwareMSC MSC_Update;\nbool MSC_Updating_Flag = false;\n\n// Button2 Obj\nButton2 btn;\n\nfloat limit = 0.0;\n\nvoid setup() {\n  digitalWrite(PD_CFG_0, LOW);\n  digitalWrite(PD_CFG_1, HIGH);\n  digitalWrite(PD_CFG_2, LOW);\n\n  // pinMode(14, INPUT);\n  // pinMode(13, INPUT);\n  // QC.set12V();\n  Serial.begin(115200);\n  Serial.setTxTimeoutMs(0);\n  // delay(5000);\n\n  //  analogSetAttenuation(ADC_11db);\n  //  vref_adc0 = calibrate_adc(ADC_UNIT_1, (adc_atten_t)ADC1_CHANNEL_5);\n  //  vref_adc1 = calibrate_adc(ADC_UNIT_2, (adc_atten_t)ADC2_CHANNEL_9);\n  adc_sensor.attach(SENSOR_PIN);\n  adc_vin.attach(VIN_PIN);\n\n  /*#if defined(MPU)\n    mpu6050.begin();\n    mpu6050.calcGyroOffsets(true);*/\n\n  // #endif\n\n  // set the pin modes 设置引脚模式\n  pinMode(SENSOR_PIN, INPUT_PULLUP);\n  // pinMode(VIN_PIN, INPUT);\n  pinMode(BUZZER_PIN, OUTPUT);\n  // pinMode(CONTROL_PIN, OUTPUT);\n  pinMode(BUTTON_P_PIN, INPUT_PULLUP);\n  pinMode(BUTTON_N_PIN, INPUT_PULLUP);\n  pinMode(BUTTON_PIN, INPUT_PULLUP);\n\n  // digitalWrite(BUZZER_PIN, LOW);        // must be LOW when buzzer not in\n  // use当蜂鸣器不使用时，必须是低电平\n\n  // get default values from EEPROM 从EEPROM获取默认值\n  //  if (!EEPROM.begin(EEPROM_SIZE))\n  //  {\n  //    Serial.println(\"failed to initialise EEPROM\");\n  //    delay(100);\n  //  }\n  init_EEPROM();\n  if (digitalRead(BUTTON_P_PIN) == LOW && digitalRead(BUTTON_N_PIN) == LOW &&\n      digitalRead(BUTTON_PIN) == HIGH) {\n    write_default_EEPROM();\n  }\n  getEEPROM();\n\n  pinMode(PD_CFG_0, OUTPUT);\n  pinMode(PD_CFG_1, OUTPUT);\n  pinMode(PD_CFG_2, OUTPUT);\n\n  if (QCEnable) {\n    QC.begin();\n    delay(100);\n    switch (VoltageValue) {\n      case 0: {\n        QC.set9V();\n      } break;\n      case 1: {\n        QC.set12V();\n      } break;\n      case 2: {\n        QC.set12V();\n      } break;\n      case 3: {\n        QC.set20V();\n      } break;\n      case 4: {\n        QC.set20V();\n      } break;\n      default:\n        break;\n    }\n  }\n\n  PD_Update();\n\n  // read supply voltages in mV 以mV为单位读取电源电压\n  delay(100);\n  Vin = getVIN();\n\n  // read and set current iron temperature 读取和设置当前的烙铁头温度\n  SetTemp = DefaultTemp;\n  RawTemp = denoiseAnalog(SENSOR_PIN);\n\n  calculateTemp();\n\n  // turn on heater if iron temperature is well below setpoint\n  // 如果烙铁头温度远低于设定值，则打开加热器\n  limit = POWER_LIMIT_20;\n  if (VoltageValue < 3) {\n    limit = POWER_LIMIT_15;\n  }\n  if (((CurrentTemp + 20) < DefaultTemp) && !inLockMode)\n    ledcWrite(CONTROL_CHANNEL, constrain(HEATER_ON, 0, limit));\n\n  // set PID output range and start the PID\n  // 设置PID输出范围，启动PID\n  ctrl.SetOutputLimits(0, 255);\n  ctrl.SetMode(AUTOMATIC);\n\n  // set initial rotary encoder values 设置旋转编码器的初始值\n  // a0 = PINB & 1; b0 = PIND >> 7 & 1; ab0 = (a0 == b0);\n  a0 = 0;\n  b0 = 0;\n  setRotary(TEMP_MIN, TEMP_MAX, TEMP_STEP, DefaultTemp);\n\n  // reset sleep timer 睡眠定时器重置\n  sleepmillis = millis();\n\n  // long beep for setup completion 安装完成时长哔哔声\n  beep();\n  beep();\n  //  delay(2000);\n  Serial.println(\"Soldering Pen\");\n  // #elif defined(LIS)\n  //   u8g2.setBusClock(100000);\n  Wire.begin();\n  Wire.setClock(100000);  // 400000\n  if (accel.begin() == false) {\n    delay(500);\n    Serial.println(\"Accelerometer not detected.\");\n  }\n  // lis2dh12_block_data_update_set(&(accel.dev_ctx), PROPERTY_DISABLE);\n  // accel.setScale(LIS2DH12_2g);\n  // accel.setMode(LIS2DH12_HR_12bit);\n  // accel.setDataRate(LIS2DH12_ODR_400Hz);\n  // lis2dh12_fifo_mode_set(&(accel.dev_ctx), LIS2DH12_BYPASS_MODE);\n\n  ChipTemp = getChipTemp();\n  lastSENSORTmp = getMPUTemp();\n  u8g2.initDisplay();\n  u8g2.begin();\n  u8g2.sendF(\"ca\", 0xa8, 0x3f);\n  u8g2.enableUTF8Print();\n  if(hand_side){\n    u8g2.setDisplayRotation(U8G2_R3);\n  }else{\n    u8g2.setDisplayRotation(U8G2_R1);\n  }\n\n\n  // btn.begin(BUTTON_PIN);\n  // btn.setDoubleClickHandler(turnOffHeater);\n  // btn.setDebounceTime(25);\n}\n\nint SENSORCheckTimes = 0;\nlong lastMillis = 0;\n\nvoid loop() {\n  long timems = millis();\n  ROTARYCheck();  // check rotary encoder (temp/boost setting, enter setup menu)\n                  // 检查旋转编码器(温度/升压设置，进入设置菜单)\n  SLEEPCheck();  // check and activate/deactivate sleep modes\n                 // 检查和激活/关闭睡眠模式\n\n  if (SENSORCheckTimes > 1) {\n    // long timems = millis();\n    SENSORCheck();  // reads temperature and vibration switch of the iron\n                    // 读取烙铁头的温度和振动开关\n    // lastMillis = millis() - timems;\n    // Serial.println(lastMillis);\n    SENSORCheckTimes = 0;\n  }\n  SENSORCheckTimes++;\n\n  Thermostat();  // heater control 加热器控制\n  MainScreen();  // updates the main page on the OLED 刷新OLED主界面\n  lastMillis = millis() - timems;\n  Serial.println(lastMillis);\n}\n\n// check rotary encoder; set temperature, toggle boost mode, enter setup menu\n// accordingly 检查旋转编码器;设置温度，切换升压模式，进入设置菜单相应\nvoid ROTARYCheck() {\n  // set working temperature according to rotary encoder value\n  // 根据旋转编码器值设定工作温度\n  SetTemp = getRotary();\n\n  uint8_t c = digitalRead(BUTTON_PIN);\n  if (!c && c0) {\n    delay(10);\n    if (digitalRead(BUTTON_PIN) == c) {\n      beep();\n      buttonmillis = millis();\n      delay(10);\n      while ((!digitalRead(BUTTON_PIN)) && ((millis() - buttonmillis) < 500))\n        ;\n      delay(10);\n      if ((millis() - buttonmillis) >= 500) {\n        SetupScreen();\n      } else {\n        if (inLockMode) {\n          inLockMode = false;\n        } else {\n          buttonmillis = millis();\n          while ((digitalRead(BUTTON_PIN)) && ((millis() - buttonmillis) < 200))\n            delay(10);\n          if ((millis() - buttonmillis) >= 200) {  // single click\n            if (inOffMode) {\n              inOffMode = false;\n            } else {\n              inBoostMode = !inBoostMode;\n              if (inBoostMode) {\n                boostmillis = millis();\n              }\n              handleMoved = true;\n            }\n          } else {  // double click\n            inOffMode = true;\n          }\n        }\n      }\n    }\n  }\n  c0 = c;\n\n  // check timer when in boost mode 在升温模式时检查计时器\n  if (inBoostMode && timeOfBoost) {\n    goneSeconds = (millis() - boostmillis) / 1000;\n    if (goneSeconds >= timeOfBoost) {\n      inBoostMode = false;  // stop boost mode 停止升温模式\n      beep();  // beep if boost mode is over 如果升温模式结束，会发出蜂鸣声\n      beepIfWorky = true;  // beep again when working temperature is reached\n                           // 当达到工作温度，会发出蜂鸣声\n    }\n  }\n}\n\n// check and activate/deactivate sleep modes 检查和激活/关闭睡眠模式\nvoid SLEEPCheck() {\n  if (inLockMode) {\n    ;\n  } else {\n    if (handleMoved) {  // if handle was moved 如果手柄被移动\n      u8g2.setPowerSave(0);\n      if (inSleepMode) {  // in sleep or off mode? 在睡眠模式还是关机模式?\n        limit = POWER_LIMIT_20;\n        if (VoltageValue < 3) {\n          limit = POWER_LIMIT_15;\n        }\n        if ((CurrentTemp + 20) <\n            SetTemp)  // if temp is well below setpoint 如果温度远低于设定值\n          ledcWrite(\n              CONTROL_CHANNEL,\n              constrain(HEATER_ON, 0, limit));  // then start the heater right\n                                                // now 那现在就启动加热器\n        beep();              // beep on wake-up\n        beepIfWorky = true;  // beep again when working temperature is reached\n                             // 当达到工作温度，会发出蜂鸣声\n      }\n      handleMoved = false;  // reset handleMoved flag\n      inSleepMode = false;  // reset sleep flag\n      //      inOffMode = false;      // reset off flag\n      sleepmillis = millis();  // reset sleep timer\n    }\n\n    // check time passed since the handle was moved 检查把手被移动后经过的时间\n    goneSeconds = (millis() - sleepmillis) / 1000;\n    if ((!inSleepMode) && (time2sleep > 0) && (goneSeconds >= time2sleep)) {\n      inSleepMode = true;\n      beep();\n    } else if ((!inOffMode) && (time2off > 0) &&\n               ((goneSeconds / 60) >= time2off)) {\n      inOffMode = true;\n      u8g2.setPowerSave(1);\n      beep();\n    }\n  }\n}\n\n// reads temperature, vibration switch and supply voltages\n// 读取温度，振动开关和电源电压\nvoid SENSORCheck() {\n  /*#if defined(MPU)\n    mpu6050.update();\n    if (abs(mpu6050.getGyroX() - gx) > WAKEUP_THRESHOLD ||\n    abs(mpu6050.getGyroY() - gy) > WAKEUP_THRESHOLD || abs(mpu6050.getGyroZ() -\n    gz) > WAKEUP_THRESHOLD)\n    {\n      gx = mpu6050.getGyroX();\n      gy = mpu6050.getGyroY();\n      gz = mpu6050.getGyroZ();\n      handleMoved = true;\n      Serial.println(\"进入工作状态!\");\n    }*/\n  // #if defined(LIS)\n\n  // if (abs(accel.getX() - gx) > WAKEUPthreshold ||\n  //     abs(accel.getY() - gy) > WAKEUPthreshold ||\n  //     abs(accel.getZ() - gz) > WAKEUPthreshold) {\n  //   gx = accel.getX();\n  //   gy = accel.getY();\n  //   gz = accel.getZ();\n  //   handleMoved = true;\n  //   //    Serial.println(\"进入工作状态!\");\n  // }\n\n  // accel.getRawX() return int16_t\n\n  if (accel.available()) {\n    accels[accelIndex][0] = accel.getRawX() + 32768;\n    accels[accelIndex][1] = accel.getRawY() + 32768;\n    accels[accelIndex][2] = accel.getRawZ() + 32768;\n    accelIndex++;\n\n    // debug output\n    // Serial.print(\"X: \");\n    // Serial.print(accels[accelIndex][0]);\n    // Serial.print(\" Y: \");\n    // Serial.print(accels[accelIndex][1]);\n    // Serial.print(\" Z: \");\n    // Serial.println(accels[accelIndex][2]);\n\n    if (accelIndex >= ACCEL_SAMPLES) {\n      accelIndex = 0;\n      // cal variance\n      uint64_t avg[3] = {0, 0, 0};\n      for (int i = 0; i < ACCEL_SAMPLES; i++) {\n        avg[0] += accels[i][0];\n        avg[1] += accels[i][1];\n        avg[2] += accels[i][2];\n      }\n      avg[0] /= ACCEL_SAMPLES;\n      avg[1] /= ACCEL_SAMPLES;\n      avg[2] /= ACCEL_SAMPLES;\n      uint64_t var[3] = {0, 0, 0};\n      for (int i = 0; i < ACCEL_SAMPLES; i++) {\n        var[0] += (accels[i][0] - avg[0]) * (accels[i][0] - avg[0]);\n        var[1] += (accels[i][1] - avg[1]) * (accels[i][1] - avg[1]);\n        var[2] += (accels[i][2] - avg[2]) * (accels[i][2] - avg[2]);\n      }\n      var[0] /= ACCEL_SAMPLES;\n      var[1] /= ACCEL_SAMPLES;\n      var[2] /= ACCEL_SAMPLES;\n      // debug output\n      // Serial.print(\"variance: \");\n      // Serial.print(var[0]);\n      // Serial.print(\" \");\n      // Serial.print(var[1]);\n      // Serial.print(\" \");\n      // Serial.println(var[2]);\n\n      int varThreshold = WAKEUPthreshold * 10000;\n\n      if (var[0] > varThreshold || var[1] > varThreshold ||\n          var[2] > varThreshold) {\n        handleMoved = true;\n        //      Serial.println(\"进入工作状态!\");\n      }\n    }\n  }\n\n  // #endif\n\n  ledcWrite(CONTROL_CHANNEL,\n            HEATER_OFF);  // shut off heater in order to measure\n                          // temperature 关闭加热器以测量温度\n  if (VoltageValue == 3) {\n    delayMicroseconds(TIME2SETTLE_20V);\n  } else {\n    delayMicroseconds(TIME2SETTLE);  // wait for voltage to settle 等待电压稳定\n  }\n  long timems = millis();\n  double temp = denoiseAnalog(SENSOR_PIN);  // 读取ADC值的温度\n  lastMillis = millis() - timems;\n  // Serial.println(lastMillis);\n\n  if (SensorCounter++ > 10) {\n    Vin = getVIN();  // get Vin every now and then 时不时去获取VIN电压\n    SensorCounter = 0;\n  }\n\n  if (!inLockMode) {\n    limit = POWER_LIMIT_20;\n    if (VoltageValue < 3) {\n      limit = POWER_LIMIT_15;\n    }\n    ledcWrite(CONTROL_CHANNEL,\n              constrain(HEATER_PWM, 0,\n                        limit));  // turn on again heater 再次打开加热器\n  }\n\n  RawTemp += (temp - RawTemp) *\n             SMOOTHIE;  // stabilize ADC temperature reading 稳定ADC温度读数\n  calculateTemp();  // calculate real temperature value 计算实际温度值\n\n  // stabilize displayed temperature when around setpoint\n  // 稳定显示温度时，周围的设定值\n  if ((ShowTemp != Setpoint) || (abs(ShowTemp - CurrentTemp) > 5))\n    ShowTemp = CurrentTemp;\n  if (abs(ShowTemp - Setpoint) <= 1) ShowTemp = Setpoint;\n  if (inLockMode) {\n    ShowTemp = 0;\n  }\n\n  // set state variable if temperature is in working range; beep if working\n  // temperature was just reached\n  // 温度在工作范围内可设置状态变量;当工作温度刚刚达到时，会发出蜂鸣声\n  gap = abs(SetTemp - CurrentTemp);\n  if (gap < 5) {\n    if (!isWorky && beepIfWorky) beep();\n    isWorky = true;\n    beepIfWorky = false;\n  } else\n    isWorky = false;\n\n  // checks if tip is present or currently inserted\n  // 检查烙铁头是否存在或当前已插入\n  if (ShowTemp > 500) TipIsPresent = false;  // tip removed ? 烙铁头移除？\n  if (!TipIsPresent &&\n      (ShowTemp < 500)) {  // new tip inserted ? 新的烙铁头插入？\n    ledcWrite(CONTROL_CHANNEL, HEATER_OFF);  // shut off heater 关闭加热器\n    beep();                                  // beep for info\n    TipIsPresent = true;  // tip is present now 烙铁头已经存在\n    ChangeTipScreen();  // show tip selection screen 显示烙铁头选择屏幕\n    updateEEPROM();     // update setting in EEPROM EEPROM的更新设置\n    handleMoved = true;  // reset all timers 重置所有计时器\n    RawTemp = denoiseAnalog(\n        SENSOR_PIN);  // restart temp smooth algorithm 重启临时平滑算法\n    c0 = LOW;         // switch must be released 必须松开开关\n    setRotary(TEMP_MIN, TEMP_MAX, TEMP_STEP,\n              SetTemp);  // reset rotary encoder 重置旋转编码器\n  }\n}\n\n// calculates real temperature value according to ADC reading and calibration\n// values 根据ADC读数和校准值，计算出真实的温度值\nvoid calculateTemp() {\n  if (RawTemp < 200)\n    CurrentTemp = map(RawTemp, 0, 200, 15, CalTemp[CurrentTip][0]);\n  else if (RawTemp < 280)\n    CurrentTemp =\n        map(RawTemp, 200, 280, CalTemp[CurrentTip][0], CalTemp[CurrentTip][1]);\n  else\n    CurrentTemp =\n        map(RawTemp, 280, 360, CalTemp[CurrentTip][1], CalTemp[CurrentTip][2]);\n}\n\n// controls the heater 控制加热器\nvoid Thermostat() {\n  // define Setpoint acoording to current working mode\n  // 根据当前工作模式定义设定值\n  if (inOffMode || inLockMode)\n    Setpoint = 0;\n  else if (inSleepMode)\n    Setpoint = SleepTemp;\n  else if (inBoostMode) {\n    Setpoint = constrain(SetTemp + BoostTemp, 0, 450);\n  } else\n    Setpoint = SetTemp;\n\n  if (SetTemp != DefaultTemp) {\n    DefaultTemp = SetTemp;  // 把设置里面的默认温度也修改了\n    update_default_temp_EEPROM();\n  }\n\n  // control the heater (PID or direct) 控制加热器(PID或直接)\n  gap = abs(Setpoint - CurrentTemp);\n  if (PIDenable) {\n    Input = CurrentTemp;\n    if (gap < 30)\n      ctrl.SetTunings(consKp, consKi, consKd);\n    else\n      ctrl.SetTunings(aggKp, aggKi, aggKd);\n    ctrl.Compute();\n  } else {\n    // turn on heater if current temperature is below setpoint\n    // 如果当前温度低于设定值，则打开加热器\n    if ((CurrentTemp + 0.5) < Setpoint)\n      Output = 0;\n    else\n      Output = 255;\n  }\n  limit = POWER_LIMIT_20;\n  if (VoltageValue < 3) {\n    limit = POWER_LIMIT_15;\n  } else if(VoltageValue == 3){\n    limit = POWER_LIMIT_20_2;\n  }\n  ledcWrite(CONTROL_CHANNEL,\n            constrain((HEATER_PWM), 0, limit));  // set heater PWM 设置加热器PWM\n}\n\n// creates a short beep on the buzzer 在蜂鸣器上创建一个短的哔哔声\nvoid beep() {\n  if (beepEnable) {\n    for (uint8_t i = 0; i < 255; i++) {\n      digitalWrite(BUZZER_PIN, HIGH);\n      delayMicroseconds(125);\n      digitalWrite(BUZZER_PIN, LOW);\n      delayMicroseconds(125);\n    }\n  }\n}\n\n// sets start values for rotary encoder 设置旋转编码器的起始值\nvoid setRotary(int rmin, int rmax, int rstep, int rvalue) {\n  countMin = rmin << ROTARY_TYPE;\n  countMax = rmax << ROTARY_TYPE;\n  countStep = rstep;\n  count = rvalue << ROTARY_TYPE;\n}\n\n// reads current rotary encoder value 读取当前旋转编码器值\nint getRotary() {\n  Button_loop();\n  return (count >> ROTARY_TYPE);\n}\n\n// reads user settings from EEPROM; if EEPROM values are invalid, write defaults\n// 从EEPROM读取用户设置;如果EEPROM值无效，则写入默认值\nvoid getEEPROM() { read_EEPROM(); }\n\n// writes user settings to EEPROM using updade function to minimize write cycles\n// 使用升级功能将用户设置写入EEPROM，以最小化写入周期\nvoid updateEEPROM() { update_EEPROM(); }\n\n// draws the main screen 绘制主屏幕\nvoid MainScreen() {\n  u8g2.firstPage();\n  do {\n    // u8g2.setCursor(0, 0);\n    // u8g2.print(F(\"nihao\"));\n    //  draw setpoint temperature\n    u8g2.setFont(PTS200_16);\n    if(language == 2){\n      u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    }\n    u8g2.setFontPosTop();\n    //    u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, \"设温:\");\n    u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, txt_set_temp[language]);\n    u8g2.setCursor(40, 0 + SCREEN_OFFSET);\n    u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    u8g2.print(Setpoint, 0);\n\n    u8g2.setFont(PTS200_16);\n    if(language == 2){\n      u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    }\n    // draw status of heater 绘制加热器状态\n    u8g2.setCursor(96, 0 + SCREEN_OFFSET);\n    if (ShowTemp > 500)\n      u8g2.print(txt_error[language]);\n    else if (inOffMode || inLockMode)\n      u8g2.print(txt_off[language]);\n    else if (inSleepMode)\n      u8g2.print(txt_sleep[language]);\n    else if (inBoostMode)\n      u8g2.print(txt_boost[language]);\n    else if (isWorky)\n      u8g2.print(txt_worky[language]);\n    else if (Output < 180)\n      u8g2.print(txt_on[language]);\n    else\n      u8g2.print(txt_hold[language]);\n\n    u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    // rest depending on main screen type 休息取决于主屏幕类型\n    if (MainScrType) {\n      // draw current tip and input voltage 绘制当前烙铁头及输入电压\n      float fVin = (float)Vin / 1000;  // convert mv in V\n      newSENSORTmp = newSENSORTmp + 0.01 * getMPUTemp();\n      SENSORTmpTime++;\n      if (SENSORTmpTime >= 100) {\n        lastSENSORTmp = newSENSORTmp;\n        newSENSORTmp = 0;\n        SENSORTmpTime = 0;\n      }\n      u8g2.setCursor(0, 50);\n      u8g2.print(lastSENSORTmp, 1);\n      u8g2.print(F(\"C\"));\n      u8g2.setCursor(83, 50);\n      u8g2.print(fVin, 1);\n      u8g2.print(F(\"V\"));\n      // draw current temperature 绘制当前温度\n      u8g2.setFont(u8g2_font_freedoomr25_tn);\n      u8g2.setFontPosTop();\n      u8g2.setCursor(37, 18);\n      if (ShowTemp > 500)\n        u8g2.print(F(\"000\"));\n      else\n        u8g2.printf(\"%03d\", ShowTemp);\n    } else {\n      // draw current temperature in big figures 用大数字绘制当前温度\n      u8g2.setFont(u8g2_font_fub42_tn);\n      u8g2.setFontPosTop();\n      u8g2.setCursor(15, 20);\n      if (ShowTemp > 500)\n        u8g2.print(F(\"000\"));\n      else\n        u8g2.printf(\"%03d\", ShowTemp);\n    }\n  } while (u8g2.nextPage());\n}\n\n// setup screen 设置屏幕\nvoid SetupScreen() {\n  ledcWrite(CONTROL_CHANNEL, HEATER_OFF);  // shut off heater\n  beep();\n  uint16_t SaveSetTemp = SetTemp;\n  uint8_t selection = 0;\n  bool repeat = true;\n\n  while (repeat) {\n    selection = MenuScreen(SetupItems, sizeof(SetupItems), selection);\n    switch (selection) {\n      case 0: {\n        TipScreen();\n        repeat = false;\n      } break;\n      case 1: {\n        TempScreen();\n      } break;\n      case 2: {\n        TimerScreen();\n      } break;\n        //      case 3:\n        //        PIDenable = MenuScreen(ControlTypeItems,\n        //        sizeof(ControlTypeItems), PIDenable); break;\n      case 3: {\n        MainScrType =\n            MenuScreen(MainScreenItems, sizeof(MainScreenItems), MainScrType);\n      } break;\n      case 4: {\n        InfoScreen();\n      } break;\n      case 5:\n        VoltageValue =\n            MenuScreen(VoltageItems, sizeof(VoltageItems), VoltageValue);\n        PD_Update();\n        break;\n      case 6:\n        QCEnable = MenuScreen(QCItems, sizeof(QCItems), QCEnable);\n        break;\n      case 7:\n        beepEnable = MenuScreen(BuzzerItems, sizeof(BuzzerItems), beepEnable);\n        break;\n      case 8: {\n        restore_default_config = MenuScreen(DefaultItems, sizeof(DefaultItems),\n                                            restore_default_config);\n        if (restore_default_config) {\n          restore_default_config = false;\n          write_default_EEPROM();\n          read_EEPROM();\n        }\n      } break;\n      case 9: {\n        bool lastbutton = (!digitalRead(BUTTON_PIN));\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(0, 10,\n                     \"MSC Update\");  // write something to the internal memory\n        u8g2.sendBuffer();           // transfer internal memory to the display\n        delay(1000);\n        do {\n          MSC_Update.onEvent(usbEventCallback);\n          MSC_Update.begin();\n          if (lastbutton && digitalRead(BUTTON_PIN)) {\n            delay(10);\n            lastbutton = false;\n          }\n        } while (digitalRead(BUTTON_PIN) || lastbutton);\n\n        MSC_Update.end();\n      } break;\n      case 10: {\n        Serial.println(language);\n        language = MenuScreen(LanguagesItems, sizeof(LanguagesItems), language);\n        Serial.println(language);\n        repeat = false;\n      } break;\n      case 11: {\n        if(hand_side == 0){\n          u8g2.setDisplayRotation(U8G2_R3);\n          hand_side = 1;\n        }else{\n          u8g2.setDisplayRotation(U8G2_R1);\n          hand_side = 0;\n        }\n        repeat = false;\n      } break;\n      default:\n        repeat = false;\n        break;\n    }\n  }\n  updateEEPROM();\n  handleMoved = true;\n  SetTemp = SaveSetTemp;\n  setRotary(TEMP_MIN, TEMP_MAX, TEMP_STEP, SetTemp);\n}\n\n// tip settings screen 烙铁头设置屏幕\nvoid TipScreen() {\n  uint8_t selection = 0;\n  bool repeat = true;\n  while (repeat) {\n    selection = MenuScreen(TipItems, sizeof(TipItems), selection);\n    switch (selection) {\n      case 0:\n        ChangeTipScreen();\n        break;\n      case 1:\n        CalibrationScreen();\n        break;\n      case 2:\n        InputNameScreen();\n        break;\n      case 3:\n        DeleteTipScreen();\n        break;\n      case 4:\n        AddTipScreen();\n        break;\n      default:\n        repeat = false;\n        break;\n    }\n  }\n}\n\n// temperature settings screen 温度设置屏幕\nvoid TempScreen() {\n  uint8_t selection = 0;\n  bool repeat = true;\n  while (repeat) {\n    selection = MenuScreen(TempItems, sizeof(TempItems), selection);\n    switch (selection) {\n      case 0:\n        setRotary(TEMP_MIN, TEMP_MAX, TEMP_STEP, DefaultTemp);\n        DefaultTemp = InputScreen(DefaultTempItems);\n        break;\n      case 1:\n        setRotary(50, TEMP_MAX, TEMP_STEP, SleepTemp);\n        SleepTemp = InputScreen(SleepTempItems);\n        break;\n      case 2:\n        setRotary(10, 100, TEMP_STEP, BoostTemp);\n        BoostTemp = InputScreen(BoostTempItems);\n        break;\n      default:\n        repeat = false;\n        break;\n    }\n  }\n}\n\n// timer settings screen 定时器设置屏幕\nvoid TimerScreen() {\n  uint8_t selection = 0;\n  bool repeat = true;\n  while (repeat) {\n    selection = MenuScreen(TimerItems, sizeof(TimerItems), selection);\n    switch (selection) {\n      case 0:\n        setRotary(0, 600, 10, time2sleep);\n        time2sleep = InputScreen(SleepTimerItems);\n        break;\n      case 1:\n        setRotary(0, 60, 1, time2off);\n        time2off = InputScreen(OffTimerItems);\n        break;\n      case 2:\n        setRotary(0, 180, 10, timeOfBoost);\n        timeOfBoost = InputScreen(BoostTimerItems);\n        break;\n      case 3:\n        setRotary(0, 50, 5, WAKEUPthreshold);\n        WAKEUPthreshold = InputScreen(WAKEUPthresholdItems);\n        break;\n      default:\n        repeat = false;\n        break;\n    }\n  }\n}\n\n// menu screen 菜单屏幕\nuint8_t MenuScreen(const char *Items[][language_types], uint8_t numberOfItems,\n                   uint8_t selected) {\n  // Serial.println(numberOfItems);\n  bool isTipScreen = ((strcmp(Items[0][language], \"烙铁头:\") == 0) ||\n                      (strcmp(Items[0][language], \"Tip:\") == 0) ||\n                      (strcmp(Items[0][language], \"烙鐵頭:\") == 0));\n  uint8_t lastselected = selected;\n  int8_t arrow = 0;\n  if (selected) arrow = 1;\n  numberOfItems = numberOfItems / language_types;\n  numberOfItems >>= 2;\n\n  // 根据OLED控制器设置选择方向\n#if defined(SSD1306)\n  setRotary(0, numberOfItems + 3, 1, selected);\n#elif defined(SH1107)\n  setRotary(0, numberOfItems - 2, 1, selected);\n#else\n#error Wrong OLED controller type!\n#endif\n\n  bool lastbutton = (!digitalRead(BUTTON_PIN));\n\n  do {\n    selected = getRotary();\n    arrow = constrain(arrow + selected - lastselected, 0, 2);\n    lastselected = selected;\n    u8g2.firstPage();\n    do {\n      u8g2.setFont(PTS200_16);\n    if(language == 2){\n      u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    }\n      u8g2.setFontPosTop();\n      u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, Items[0][language]);\n      if (isTipScreen)\n        u8g2.drawUTF8(54, 0 + SCREEN_OFFSET, TipName[CurrentTip]);\n      u8g2.drawUTF8(0, 16 * (arrow + 1) + SCREEN_OFFSET, \">\");\n      for (uint8_t i = 0; i < 3; i++) {\n        uint8_t drawnumber = selected + i + 1 - arrow;\n        if (drawnumber < numberOfItems)\n          u8g2.drawUTF8(12, 16 * (i + 1) + SCREEN_OFFSET,\n                        Items[selected + i + 1 - arrow][language]);\n      }\n    } while (u8g2.nextPage());\n    if (lastbutton && digitalRead(BUTTON_PIN)) {\n      delay(10);\n      lastbutton = false;\n    }\n  } while (digitalRead(BUTTON_PIN) || lastbutton);\n\n  beep();\n  return selected;\n}\n\nvoid MessageScreen(const char *Items[][language_types], uint8_t numberOfItems) {\n  numberOfItems = numberOfItems / language_types;\n  bool lastbutton = (!digitalRead(BUTTON_PIN));\n  u8g2.firstPage();\n  do {\n    u8g2.setFont(PTS200_16);\n        if(language == 2){\n      u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    }\n    u8g2.setFontPosTop();\n    for (uint8_t i = 0; i < numberOfItems; i++)\n      u8g2.drawUTF8(0, i * 16, Items[i][language]);\n  } while (u8g2.nextPage());\n  do {\n    if (lastbutton && digitalRead(BUTTON_PIN)) {\n      delay(10);\n      lastbutton = false;\n    }\n  } while (digitalRead(BUTTON_PIN) || lastbutton);\n  beep();\n}\n\n// input value screen 输入值屏幕\nuint16_t InputScreen(const char *Items[][language_types]) {\n  uint16_t value;\n  bool lastbutton = (!digitalRead(BUTTON_PIN));\n\n  do {\n    value = getRotary();\n    u8g2.firstPage();\n    do {\n      u8g2.setFont(PTS200_16);\n          if(language == 2){\n      u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    }\n      u8g2.setFontPosTop();\n      u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, Items[0][language]);\n      u8g2.setCursor(0, 32);\n      u8g2.print(\">\");\n      u8g2.setCursor(10, 32);\n      if (value == 0)\n        u8g2.print(txt_Deactivated[language]);\n      else {\n        u8g2.print(value);\n        u8g2.print(\" \");\n        u8g2.print(Items[1][language]);\n      }\n    } while (u8g2.nextPage());\n    if (lastbutton && digitalRead(BUTTON_PIN)) {\n      delay(10);\n      lastbutton = false;\n    }\n  } while (digitalRead(BUTTON_PIN) || lastbutton);\n\n  beep();\n  return value;\n}\n\n// information display screen 信息显示屏幕\nvoid InfoScreen() {\n  bool lastbutton = (!digitalRead(BUTTON_PIN));\n\n  do {\n    Vin = getVIN();                  // read supply voltage\n    float fVin = (float)Vin / 1000;  // convert mv in V\n    float fTmp = getChipTemp();      // read cold junction temperature\n    u8g2.firstPage();\n    do {\n      u8g2.setFont(PTS200_16);\n          if(language == 2){\n      u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    }\n      u8g2.setFontPosTop();\n      u8g2.setCursor(0, 0 + SCREEN_OFFSET);\n      u8g2.print(txt_temp[language]);\n      u8g2.print(fTmp, 1);\n      u8g2.print(F(\" C\"));\n      u8g2.setCursor(0, 16 + SCREEN_OFFSET);\n      u8g2.print(txt_voltage[language]);\n      u8g2.print(fVin, 1);\n      u8g2.print(F(\" V\"));\n      u8g2.setCursor(0, 16 * 2 + SCREEN_OFFSET);\n      u8g2.print(txt_Version[language]);\n      u8g2.print(VERSION);\n      // u8g2.setCursor(0, 48); u8g2.print(F(\"IMU:  \"));\n      // u8g2.print(accelerometer[1], DEC); u8g2.print(F(\"\"));\n    } while (u8g2.nextPage());\n    if (lastbutton && digitalRead(BUTTON_PIN)) {\n      delay(10);\n      lastbutton = false;\n    }\n  } while (digitalRead(BUTTON_PIN) || lastbutton);\n\n  beep();\n}\n\n// change tip screen 改变烙铁头屏幕\nvoid ChangeTipScreen() {\n  uint8_t selected = CurrentTip;\n  uint8_t lastselected = selected;\n  int8_t arrow = 0;\n  if (selected) arrow = 1;\n  setRotary(0, NumberOfTips - 1, 1, selected);\n  bool lastbutton = (!digitalRead(BUTTON_PIN));\n\n  Serial.print(\"selected: \");\n  Serial.println(selected);\n  Serial.print(\"lastselected: \\n\");\n  Serial.println(lastselected);\n  Serial.print(\"NumberOfTips: \\n\");\n  Serial.println(NumberOfTips);\n\n  do {\n    selected = getRotary();\n    arrow = constrain(arrow + selected - lastselected, 0, 2);\n    lastselected = selected;\n    u8g2.firstPage();\n    do {\n      u8g2.setFont(PTS200_16);\n          if(language == 2){\n      u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    }\n      u8g2.setFontPosTop();\n      //      strcpy_P(F_Buffer, PSTR(\"选择烙铁头\"));\n      u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, txt_select_tip[language]);\n      u8g2.drawUTF8(0, 16 * (arrow + 1) + SCREEN_OFFSET, \">\");\n      for (uint8_t i = 0; i < 3; i++) {\n        uint8_t drawnumber = selected + i - arrow;\n        if (drawnumber < NumberOfTips)\n          u8g2.drawUTF8(12, 16 * (i + 1) + SCREEN_OFFSET,\n                        TipName[selected + i - arrow]);\n      }\n    } while (u8g2.nextPage());\n    if (lastbutton && digitalRead(BUTTON_PIN)) {\n      delay(10);\n      lastbutton = false;\n    }\n  } while (digitalRead(BUTTON_PIN) || lastbutton);\n\n  beep();\n  CurrentTip = selected;\n}\n\n// temperature calibration screen 温度校准屏幕\nvoid CalibrationScreen() {\n  uint16_t CalTempNew[4];\n  uint16_t tempSetTemp = SetTemp;\n  for (uint8_t CalStep = 0; CalStep < 3; CalStep++) {\n    SetTemp = CalTemp[CurrentTip][CalStep];\n    Serial.print(\"SetTemp: \");\n    Serial.println(SetTemp);\n    setRotary(100, 500, 1, SetTemp);\n    beepIfWorky = true;\n    bool lastbutton = (!digitalRead(BUTTON_PIN));\n\n    do {\n      SENSORCheck();  // reads temperature and vibration switch of the iron\n                      // 读取烙铁头的温度和振动开关\n      Thermostat();   // heater control\n\n      u8g2.firstPage();\n      do {\n        u8g2.setFont(PTS200_16);\n            if(language == 2){\n      u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    }\n        u8g2.setFontPosTop();\n        //        strcpy_P(F_Buffer, PSTR(\"校准\"));\n        u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, txt_calibrate[language]);\n        u8g2.setCursor(0, 16 + SCREEN_OFFSET);\n        u8g2.print(txt_step[language]);\n        u8g2.print(CalStep + 1);\n        u8g2.print(\" of 3\");\n        if (isWorky) {\n          u8g2.setCursor(0, 32 + SCREEN_OFFSET);\n          u8g2.print(txt_set_measured[language]);\n          u8g2.setCursor(0, 48 + SCREEN_OFFSET);\n          u8g2.print(txt_s_temp[language]);\n          u8g2.print(getRotary());\n        } else {\n          u8g2.setCursor(0, 32 + SCREEN_OFFSET);\n          u8g2.print(txt_temp_2[language]);\n          u8g2.print(uint16_t(RawTemp));\n          u8g2.setCursor(0, 48 + SCREEN_OFFSET);\n          u8g2.print(txt_wait_pls[language]);\n        }\n      } while (u8g2.nextPage());\n      if (lastbutton && digitalRead(BUTTON_PIN)) {\n        delay(10);\n        lastbutton = false;\n      }\n    } while (digitalRead(BUTTON_PIN) || lastbutton);\n\n    CalTempNew[CalStep] = getRotary();\n    beep();\n    delay(10);\n  }\n\n  ledcWrite(CONTROL_CHANNEL, HEATER_OFF);  // shut off heater 关闭加热器\n  if (VoltageValue == 3) {\n    delayMicroseconds(TIME2SETTLE_20V);\n  } else {\n    delayMicroseconds(TIME2SETTLE);  // wait for voltage to settle 等待电压稳定\n  }\n  CalTempNew[3] = getChipTemp();  // read chip temperature 读芯片温度\n  if ((CalTempNew[0] + 10 < CalTempNew[1]) &&\n      (CalTempNew[1] + 10 < CalTempNew[2])) {\n    if (MenuScreen(StoreItems, sizeof(StoreItems), 0)) {\n      for (uint8_t i = 0; i < 4; i++) CalTemp[CurrentTip][i] = CalTempNew[i];\n    }\n  }\n\n  SetTemp = tempSetTemp;\n  update_EEPROM();\n}\n\n// input tip name screen 输入烙铁头名字屏幕\nvoid InputNameScreen() {\n  uint8_t value;\n\n  for (uint8_t digit = 0; digit < (TIPNAMELENGTH - 1); digit++) {\n    bool lastbutton = (!digitalRead(BUTTON_PIN));\n    setRotary(31, 96, 1, 65);\n    do {\n      value = getRotary();\n      if (value == 31) {\n        value = 95;\n        setRotary(31, 96, 1, 95);\n      }\n      if (value == 96) {\n        value = 32;\n        setRotary(31, 96, 1, 32);\n      }\n      u8g2.firstPage();\n      do {\n        u8g2.setFont(PTS200_16);\n            if(language == 2){\n      u8g2.setFont(u8g2_font_unifont_t_chinese3);\n    }\n        u8g2.setFontPosTop();\n        u8g2.drawUTF8(0, 0 + SCREEN_OFFSET, txt_enter_tip_name[language]);\n        u8g2.setCursor(12 * digit, 48 + SCREEN_OFFSET);\n        u8g2.print(char(94));\n        u8g2.setCursor(0, 32 + SCREEN_OFFSET);\n        for (uint8_t i = 0; i < digit; i++) u8g2.print(TipName[CurrentTip][i]);\n        u8g2.setCursor(12 * digit, 32 + SCREEN_OFFSET);\n        u8g2.print(char(value));\n      } while (u8g2.nextPage());\n      if (lastbutton && digitalRead(BUTTON_PIN)) {\n        delay(10);\n        lastbutton = false;\n      }\n    } while (digitalRead(BUTTON_PIN) || lastbutton);\n    TipName[CurrentTip][digit] = value;\n    beep();\n    delay(10);\n  }\n  TipName[CurrentTip][TIPNAMELENGTH - 1] = 0;\n  return;\n}\n\n// delete tip screen 删除烙铁头屏幕\nvoid DeleteTipScreen() {\n  if (NumberOfTips == 1) {\n    MessageScreen(DeleteMessage, sizeof(DeleteMessage));\n  } else if (MenuScreen(SureItems, sizeof(SureItems), 0)) {\n    if (CurrentTip == (NumberOfTips - 1)) {\n      CurrentTip--;\n    } else {\n      for (uint8_t i = CurrentTip; i < (NumberOfTips - 1); i++) {\n        for (uint8_t j = 0; j < TIPNAMELENGTH; j++)\n          TipName[i][j] = TipName[i + 1][j];\n        for (uint8_t j = 0; j < 4; j++) CalTemp[i][j] = CalTemp[i + 1][j];\n      }\n    }\n    NumberOfTips--;\n  }\n}\n\n// add new tip screen 添加新的烙铁头屏幕\nvoid AddTipScreen() {\n  if (NumberOfTips < TIPMAX) {\n    CurrentTip = NumberOfTips++;\n    InputNameScreen();\n    CalTemp[CurrentTip][0] = TEMP200;\n    CalTemp[CurrentTip][1] = TEMP280;\n    CalTemp[CurrentTip][2] = TEMP360;\n    CalTemp[CurrentTip][3] = TEMPCHP;\n  } else\n    MessageScreen(MaxTipMessage, sizeof(MaxTipMessage));\n}\n\n// 对32个ADC读数进行平均以降噪\n//  VP+_Ru = 100k, Rd_GND = 1K\nuint16_t denoiseAnalog(byte port) {\n  uint32_t result = 0;\n  float maxValue, minValue;\n  int resultArray[8];\n\n  for (uint8_t i = 0; i < 8; i++) {\n    // get 32 readings and sort them 获取32个读数并对其进行排序\n    float value, raw_adc;\n\n    raw_adc = adc_sensor.readMiliVolts();\n    // value = constrain(0.4432 * raw_adc + 29.665, 20, 1000);\n    value = constrain(0.5378 * raw_adc + 6.3959, 20, 1000); // y = 0.5378x + 6.3959\n\n    resultArray[i] = value;\n  }\n\n  // sort resultArray with low time complexity\n  // 用低时间复杂度对resultArray进行排序\n  for (uint8_t i = 0; i < 8; i++) {\n    for (uint8_t j = i + 1; j < 8; j++) {\n      if (resultArray[i] > resultArray[j]) {\n        int temp = resultArray[i];\n        resultArray[i] = resultArray[j];\n        resultArray[j] = temp;\n      }\n    }\n  }\n\n  // get the average of the middle 4 readings 获取中间20个读数的平均值\n  for (uint8_t i = 2; i < 6; i++) {\n    result += resultArray[i];\n  }\n\n  //  Serial.printf(\"raw_val: %d\", adc_sensor.readMiliVolts());\n  //  Serial.println();\n  // Serial.printf(\"val: %d\", result / 4);\n  // Serial.println();\n  return (result / 4);  // devide by 32 and return value 除以32并返回值\n}\n\n// 读取SENSOR内部温度\ndouble getChipTemp() {\n#if defined(MPU)\n  mpu6050.update();\n  int16_t Temp = mpu6050.getTemp();\n#elif defined(LIS)\n  int16_t Temp = accel.getTemperature();\n#endif\n\n  return Temp;\n}\n\n// get LIS/MPU temperature 获取LIS/MPU的温度\nfloat getMPUTemp() {\n#if defined(MPU)\n  mpu6050.update();\n  int16_t Temp = mpu6050.getTemp();\n#elif defined(LIS)\n  int16_t Temp = accel.getTemperature();\n#endif\n\n  return Temp;\n}\n\n// get supply voltage in mV 得到以mV为单位的电源电压\nuint16_t getVIN() {\n  long value;\n  long voltage;\n  long result = 0;\n\n  for (uint8_t i = 0; i < 4; i++) {  // get 32 readings 得到32个读数\n    //    long val = analogRead(VIN_PIN);\n    long val = adc_vin.readMiliVolts();\n\n    result += val;  // add them up 把它们加起来\n  }\n\n  value = (result / 4);\n\n  //  // VIN_Ru = 100k, Rd_GND = 3.3K\n  //  if (value < 500)\n  //  {\n  //    voltage = value * 1390 * 31.3 / 4095 * 1.35;\n  //  }\n  //  else if (500 <= value && value < 1000)\n  //  {\n  //    voltage = value * 1390 * 31.3 / 4095 * 1.135;\n  //  }\n  //  else if (1000 <= value && value < 1500)\n  //  {\n  //    voltage = value * 1390 * 31.3 / 4095 * 1.071;\n  //  }\n  //  else if (1500 <= value && value < 2000)\n  //  {\n  //    voltage = value * 1390 * 31.3 / 4095;\n  //  }\n  //  else if (2000 <= value && value < 3000)\n  //  {\n  //    voltage = value * 1390 * 31.3 / 4095;\n  //  }\n  //  else\n  //    voltage = value * 1390 * 31.3 / 4095;\n\n  voltage = value * 31.3;\n\n  return voltage;\n  // return value;\n}\n\nint32_t variance(int16_t a[]) {\n  // Compute mean (average of elements)计算平均值(元素的平均值)\n  int32_t sum = 0;\n\n  for (int i = 0; i < 32; i++) sum += a[i];\n  int16_t mean = (int32_t)sum / 32;\n  // Compute sum squared differences with mean.计算和平方差的平均值\n  int32_t sqDiff = 0;\n  for (int i = 0; i < 32; i++) sqDiff += (a[i] - mean) * (a[i] - mean);\n  return (int32_t)sqDiff / 32;\n}\n\nunsigned int Button_Time1 = 0, Button_Time2 = 0;\n\nvoid Button_loop() {\n  if (!digitalRead(BUTTON_N_PIN) && a0 == 1) {\n    delay(BUTTON_DELAY);\n    if (!digitalRead(BUTTON_N_PIN)) {\n      int count0 = count;\n      count = constrain(count + countStep, countMin, countMax);\n      if (!(countMin == TEMP_MIN && countMax == TEMP_MAX)) {\n        if (count0 + countStep > countMax) {\n          count = countMin;\n        }\n      }\n      a0 = 0;\n    }\n  } else if (!digitalRead(BUTTON_N_PIN) && a0 == 0) {\n    delay(BUTTON_DELAY);\n    if (Button_Time1 > 10)  // 这里的数越大，需要长按时间更长\n      count = constrain(count + countStep, countMin, countMax);\n    else\n      Button_Time1++;\n  } else if (digitalRead(BUTTON_N_PIN)) {\n    Button_Time1 = 0;\n    a0 = 1;\n  }\n\n  if (!digitalRead(BUTTON_P_PIN) && b0 == 1) {\n    delay(BUTTON_DELAY);\n    if (!digitalRead(BUTTON_P_PIN)) {\n      int count0 = count;\n      count = constrain(count - countStep, countMin, countMax);\n      if (!(countMin == TEMP_MIN && countMax == TEMP_MAX)) {\n        if (count0 - countStep < countMin) {\n          count = countMax;\n        }\n      }\n      b0 = 0;\n    }\n  } else if (!digitalRead(BUTTON_P_PIN) && b0 == 0) {\n    delay(BUTTON_DELAY);\n    if (Button_Time2 > 10)  // 这里的数越大，需要长按时间更长\n      count = constrain(count - countStep, countMin, countMax);\n    else\n      Button_Time2++;\n  } else if (digitalRead(BUTTON_P_PIN)) {\n    Button_Time2 = 0;\n    b0 = 1;\n  }\n}\n\nvoid PD_Update() {\n  switch (VoltageValue) {\n    case 0: {\n      digitalWrite(PD_CFG_0, LOW);\n      digitalWrite(PD_CFG_1, LOW);\n      digitalWrite(PD_CFG_2, LOW);\n    } break;\n    case 1: {\n      digitalWrite(PD_CFG_0, LOW);\n      digitalWrite(PD_CFG_1, LOW);\n      digitalWrite(PD_CFG_2, HIGH);\n    } break;\n    case 2: {\n      digitalWrite(PD_CFG_0, LOW);\n      digitalWrite(PD_CFG_1, HIGH);\n      digitalWrite(PD_CFG_2, HIGH);\n    } break;\n    case 3: {\n      digitalWrite(PD_CFG_0, LOW);\n      digitalWrite(PD_CFG_1, HIGH);\n      digitalWrite(PD_CFG_2, LOW);\n    } break;\n    case 4: {\n      digitalWrite(PD_CFG_0, LOW);\n      digitalWrite(PD_CFG_1, HIGH);\n      digitalWrite(PD_CFG_2, LOW);\n    } break;\n    default:\n      break;\n  }\n\n  if (VoltageValue == 3) {\n    ledcSetup(CONTROL_CHANNEL, CONTROL_FREQ_20V, CONTROL_RES);\n  } else {\n    ledcSetup(CONTROL_CHANNEL, CONTROL_FREQ, CONTROL_RES);\n  }\n\n  ledcAttachPin(CONTROL_PIN, CONTROL_CHANNEL);\n\n  // analogWrite(CONTROL_PIN, HEATER_OFF); // this shuts off the\n  // heater这是用来关闭加热器的\n  ledcWrite(CONTROL_CHANNEL, HEATER_OFF);\n}\n\nstatic void usbEventCallback(void *arg, esp_event_base_t event_base,\n                             int32_t event_id, void *event_data) {\n  if (event_base == ARDUINO_USB_EVENTS) {\n    // arduino_usb_event_data_t* data = (arduino_usb_event_data_t*)event_data;\n    switch (event_id) {\n      case ARDUINO_USB_STARTED_EVENT:\n        // HWSerial.println(\"USB PLUGGED\");\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(0, 10,\n                     \"USB PLUGGED\");  // write something to the internal memory\n        u8g2.sendBuffer();            // transfer internal memory to the display\n        break;\n      case ARDUINO_USB_STOPPED_EVENT:\n        // HWSerial.println(\"USB UNPLUGGED\");\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(\n            0, 10, \"USB UNPLUGGED\");  // write something to the internal memory\n        u8g2.sendBuffer();            // transfer internal memory to the display\n        break;\n      case ARDUINO_USB_SUSPEND_EVENT:\n        // HWSerial.printf(\"USB SUSPENDED: remote_wakeup_en: %u\\n\",\n        // data->suspend.remote_wakeup_en);\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(\n            0, 10, \"USB SUSPENDED\");  // write something to the internal memory\n        u8g2.sendBuffer();            // transfer internal memory to the display\n        break;\n      case ARDUINO_USB_RESUME_EVENT:\n        // HWSerial.println(\"USB RESUMED\");\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(0, 10,\n                     \"USB RESUMED\");  // write something to the internal memory\n        u8g2.sendBuffer();            // transfer internal memory to the display\n        break;\n\n      default:\n        break;\n    }\n  } else if (event_base == ARDUINO_FIRMWARE_MSC_EVENTS) {\n    // arduino_firmware_msc_event_data_t* data =\n    // (arduino_firmware_msc_event_data_t*)event_data;\n    switch (event_id) {\n      case ARDUINO_FIRMWARE_MSC_START_EVENT:\n        // HWSerial.println(\"MSC Update Start\");\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(\n            0, 10,\n            \"MSC Update Start\");  // write something to the internal memory\n        u8g2.sendBuffer();        // transfer internal memory to the display\n        break;\n      case ARDUINO_FIRMWARE_MSC_WRITE_EVENT:\n        // HWSerial.printf(\"MSC Update Write %u bytes at offset %u\\n\",\n        // data->write.size, data->write.offset);\n        //  HWSerial.print(\".\");\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(0, 10,\n                     \"MSC Updating\");  // write something to the internal memory\n        u8g2.sendBuffer();  // transfer internal memory to the display\n        break;\n      case ARDUINO_FIRMWARE_MSC_END_EVENT:\n        // HWSerial.printf(\"\\nMSC Update End: %u bytes\\n\", data->end.size);\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(\n            0, 10, \"MSC Update End\");  // write something to the internal memory\n        u8g2.sendBuffer();  // transfer internal memory to the display\n        break;\n      case ARDUINO_FIRMWARE_MSC_ERROR_EVENT:\n        // HWSerial.printf(\"MSC Update ERROR! Progress: %u bytes\\n\",\n        // data->error.size);\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(\n            0, 10,\n            \"MSC Update ERROR!\");  // write something to the internal memory\n        u8g2.sendBuffer();         // transfer internal memory to the display\n        break;\n      case ARDUINO_FIRMWARE_MSC_POWER_EVENT:\n        // HWSerial.printf(\"MSC Update Power: power: %u, start: %u, eject: %u\",\n        // data->power.power_condition, data->power.start,\n        // data->power.load_eject);\n        u8g2.clearBuffer();                  // clear the internal memory\n        u8g2.setFont(u8g2_font_ncenB08_tr);  // choose a suitable font\n        u8g2.drawStr(\n            0, 10,\n            \"MSC Update Power\");  // write something to the internal memory\n        u8g2.sendBuffer();        // transfer internal memory to the display\n        break;\n\n      default:\n        break;\n    }\n  }\n}\n\nvoid turnOffHeater(Button2 &b) { inOffMode = true; }\n\n// uint16_t calibrate_adc(adc_unit_t adc, adc_atten_t channel) {\n//   uint16_t vref;\n//   esp_adc_cal_characteristics_t adc_chars;\n//   esp_adc_cal_value_t val_type = esp_adc_cal_characterize((adc_unit_t)adc,\n//   (adc_atten_t)channel, (adc_bits_width_t)ADC_WIDTH_BIT_12, 1100,\n//   &adc_chars);\n//   //Check type of calibration value used to characterize ADC\n//   if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {\n//     Serial.printf(\"eFuse Vref:%u mV\", adc_chars.vref);\n//     Serial.println();\n//     vref = adc_chars.vref;\n//   } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {\n//     Serial.printf(\"Two Point --> coeff_a:%umV coeff_b:%umV\\n\",\n//     adc_chars.coeff_a, adc_chars.coeff_b); Serial.println();\n//   } else {\n//     Serial.println(\"Default Vref: 1100mV\");\n//   }\n//   return vref;\n// }\n\nvoid heatWithLimit() {\n  // ledcSetup(channel, hertz, resolution);\n  // ledcAttachPin(pin, channel);\n\n  limit = 0;\n  if (VoltageValue < 3) {\n    limit = POWER_LIMIT_15;\n  } else if (VoltageValue == 3) {\n    limit = POWER_LIMIT_20;\n  }\n  ledcWrite(\n      CONTROL_CHANNEL,\n      constrain(HEATER_PWM, 0, limit));  // turn on again heater 再次打开加热器\n}"
  },
  {
    "path": "SolderingPen_ESP32S2/UtilsEEPROM.h",
    "content": "#include <EEPROM.h>\n\n#define ADDR_SYSTEM_INIT_FLAG 0\n#define ADDR_DEFAULT_TEMP ADDR_SYSTEM_INIT_FLAG + 4\n#define ADDR_SLEEP_TEMP ADDR_DEFAULT_TEMP + 2\n#define ADDR_BOOST_TEMP ADDR_SLEEP_TEMP + 2\n#define ADDR_TIME_2_SLEEP ADDR_BOOST_TEMP + 1\n#define ADDR_TIME_2_OFF ADDR_TIME_2_SLEEP + 2\n#define ADDR_TIME_OF_BOOST ADDR_TIME_2_OFF + 1\n#define ADDR_MAIN_SCREEN ADDR_TIME_OF_BOOST + 1\n#define ADDR_PID_ENABLE ADDR_MAIN_SCREEN + 1\n#define ADDR_BEEP_ENABLE ADDR_PID_ENABLE + 1\n#define ADDR_VOLTAGE_VALUE ADDR_BEEP_ENABLE + 1\n#define ADDR_QC_ENABLE ADDR_VOLTAGE_VALUE + 1\n#define ADDR_WAKEUP_THRESHOLD ADDR_QC_ENABLE + 1\n#define ADDR_CURRENT_TIP ADDR_WAKEUP_THRESHOLD + 1\n#define ADDR_NUMBER_OF_TIPS ADDR_CURRENT_TIP + 1\n\n#define ADDR_TIP_NAME ADDR_NUMBER_OF_TIPS + 1\n#define ADDR_CAL_TEMP ADDR_TIP_NAME + TIPNAMELENGTH *TIPMAX\n\n#define ADDR_LANGUAGE ADDR_CAL_TEMP + 2 * CALNUM *TIPMAX\n#define ADDR_HAND_SIDE ADDR_LANGUAGE + 1\n\n#define ADDR_EEPROM_SIZE ADDR_HAND_SIDE + 1\n\nbool system_init_flag = false;\n\nextern uint16_t DefaultTemp;\nextern uint16_t SleepTemp;\nextern uint8_t BoostTemp;\nextern uint16_t time2sleep;\nextern uint8_t time2off;\nextern uint8_t timeOfBoost;\nextern uint8_t MainScrType;\nextern bool PIDenable;\nextern bool beepEnable;\nextern volatile uint8_t VoltageValue;\nextern bool QCEnable;\nextern uint8_t WAKEUPthreshold;\nextern uint8_t CurrentTip;\nextern uint8_t NumberOfTips;\n\nextern char TipName[TIPMAX][TIPNAMELENGTH];\nextern uint16_t CalTemp[TIPMAX][CALNUM];\n\nextern uint8_t language;\nextern uint8_t hand_side;\n\nbool write_default_EEPROM()\n{\n  Serial.println(\"Writing default config to EEPROM\");\n\n  EEPROM.writeUShort(ADDR_DEFAULT_TEMP, TEMP_DEFAULT);\n  EEPROM.writeUShort(ADDR_SLEEP_TEMP, TEMP_SLEEP);\n  EEPROM.writeUChar(ADDR_BOOST_TEMP, TEMP_BOOST);\n  EEPROM.writeUShort(ADDR_TIME_2_SLEEP, TIME2SLEEP);\n  EEPROM.writeUChar(ADDR_TIME_2_OFF, TIME2OFF);\n  EEPROM.writeUChar(ADDR_TIME_OF_BOOST, TIMEOFBOOST);\n  EEPROM.writeUChar(ADDR_MAIN_SCREEN, MAINSCREEN);\n  EEPROM.writeBool(ADDR_PID_ENABLE, PID_ENABLE);\n  EEPROM.writeBool(ADDR_BEEP_ENABLE, BEEP_ENABLE);\n  EEPROM.writeUChar(ADDR_VOLTAGE_VALUE, VOLTAGE_VALUE);\n  EEPROM.writeBool(ADDR_QC_ENABLE, QC_ENABLE);\n  EEPROM.writeUChar(ADDR_WAKEUP_THRESHOLD, WAKEUP_THRESHOLD);\n  EEPROM.writeUChar(ADDR_CURRENT_TIP, 0);\n  EEPROM.writeUChar(ADDR_NUMBER_OF_TIPS, 1);\n\n  CalTemp[0][0] = TEMP200;\n  CalTemp[0][1] = TEMP280;\n  CalTemp[0][2] = TEMP360;\n  CalTemp[0][3] = TEMPCHP;\n  //  TipName[0][TIPNAMELENGTH] = {TIPNAME};\n\n  for (uint8_t i = 0; i < 1; i++)\n  {\n    EEPROM.writeString(ADDR_TIP_NAME + i * TIPNAMELENGTH, TipName[i]);\n    for (uint8_t j = 0; j < CALNUM; j++)\n    {\n      EEPROM.writeUShort(ADDR_CAL_TEMP + i * 2 * CALNUM + j * 2, CalTemp[i][j]);\n    }\n  }\n\n  EEPROM.writeUChar(ADDR_LANGUAGE, DEFAULT_LANGUAGE);\n  EEPROM.writeUChar(ADDR_HAND_SIDE, DEFAULT_HAND_SIDE);\n\n  EEPROM.writeUInt(ADDR_SYSTEM_INIT_FLAG, VERSION_NUM);\n\n  if (EEPROM.commit())\n  {\n    Serial.println(\"Default config Done\");\n    return true;\n  }\n  else\n  {\n    Serial.println(\"Default config Failed\");\n    return false;\n  }\n}\n\nbool init_EEPROM()\n{\n  Serial.println(\"Initialising EEPROM\");\n  if (!EEPROM.begin(ADDR_EEPROM_SIZE))\n  {\n    Serial.println(\"Failed to initialise EEPROM\");\n    //    Serial.println(\"Restarting...\");\n    //    delay(1000);\n    //    ESP.restart();\n    return false;\n  }\n  Serial.println(\"EEPROM Done\");\n  return true;\n}\n\nbool update_EEPROM()\n{\n  Serial.println(\"Updating EEPROM\");\n\n  EEPROM.writeUShort(ADDR_DEFAULT_TEMP, DefaultTemp);\n  EEPROM.writeUShort(ADDR_SLEEP_TEMP, SleepTemp);\n  EEPROM.writeUChar(ADDR_BOOST_TEMP, BoostTemp);\n  EEPROM.writeUShort(ADDR_TIME_2_SLEEP, time2sleep);\n  EEPROM.writeUChar(ADDR_TIME_2_OFF, time2off);\n  EEPROM.writeUChar(ADDR_TIME_OF_BOOST, timeOfBoost);\n  EEPROM.writeUChar(ADDR_MAIN_SCREEN, MainScrType);\n  EEPROM.writeBool(ADDR_PID_ENABLE, PIDenable);\n  EEPROM.writeBool(ADDR_BEEP_ENABLE, beepEnable);\n  EEPROM.writeUChar(ADDR_VOLTAGE_VALUE, VoltageValue);\n  EEPROM.writeBool(ADDR_QC_ENABLE, QCEnable);\n  EEPROM.writeUChar(ADDR_WAKEUP_THRESHOLD, WAKEUPthreshold);\n  EEPROM.writeUChar(ADDR_CURRENT_TIP, CurrentTip);\n  EEPROM.writeUChar(ADDR_NUMBER_OF_TIPS, NumberOfTips);\n\n  for (uint8_t i = 0; i < NumberOfTips; i++)\n  {\n    EEPROM.writeString(ADDR_TIP_NAME + i * TIPNAMELENGTH, TipName[i]);\n    for (uint8_t j = 0; j < CALNUM; j++)\n    {\n      EEPROM.writeUShort(ADDR_CAL_TEMP + i * 2 * CALNUM + j * 2, CalTemp[i][j]);\n    }\n  }\n\n  EEPROM.writeUChar(ADDR_LANGUAGE, language);\n  EEPROM.writeUChar(ADDR_HAND_SIDE, hand_side);\n\n  EEPROM.writeUInt(ADDR_SYSTEM_INIT_FLAG, VERSION_NUM);\n\n  if (EEPROM.commit())\n  {\n    Serial.println(\"EEPROM Update Done\");\n    return true;\n  }\n  else\n  {\n    Serial.println(\"EEPROM Update Failed\");\n    return false;\n  }\n}\n\nbool read_EEPROM()\n{\n  Serial.println(\"Reading EEPROM\");\n\n  //  write_default_EEPROM();\n\n  //  system_init_flag = EEPROM.readUInt(ADDR_SYSTEM_INIT_FLAG);\n\n  if (EEPROM.readUInt(ADDR_SYSTEM_INIT_FLAG) != VERSION_NUM)\n  {\n    //    return false;\n    Serial.println(\"System didn't initialised\");\n    write_default_EEPROM();\n  }\n\n  //  EEPROM.readString(ADDR_WIFI_SSID_1).toCharArray(WiFi_SSID_1, sizeof(WiFi_SSID_1));\n\n  DefaultTemp = EEPROM.readUShort(ADDR_DEFAULT_TEMP);\n  SleepTemp = EEPROM.readUShort(ADDR_SLEEP_TEMP);\n  BoostTemp = EEPROM.readUChar(ADDR_BOOST_TEMP);\n  time2sleep = EEPROM.readUShort(ADDR_TIME_2_SLEEP);\n  time2off = EEPROM.readUChar(ADDR_TIME_2_OFF);\n  timeOfBoost = EEPROM.readUChar(ADDR_TIME_OF_BOOST);\n  MainScrType = EEPROM.readUChar(ADDR_MAIN_SCREEN);\n  PIDenable = EEPROM.readBool(ADDR_PID_ENABLE);\n  beepEnable = EEPROM.readBool(ADDR_BEEP_ENABLE);\n  VoltageValue = EEPROM.readUChar(ADDR_VOLTAGE_VALUE);\n  QCEnable = EEPROM.readBool(ADDR_QC_ENABLE);\n  WAKEUPthreshold = EEPROM.readUChar(ADDR_WAKEUP_THRESHOLD);\n  CurrentTip = EEPROM.readUChar(ADDR_CURRENT_TIP);\n  NumberOfTips = EEPROM.readUChar(ADDR_NUMBER_OF_TIPS);\n\n  for (uint8_t i = 0; i < NumberOfTips; i++)\n  {\n    EEPROM.readString(ADDR_TIP_NAME + i * TIPNAMELENGTH).toCharArray(TipName[i], sizeof(TipName[i]));\n    for (uint8_t j = 0; j < CALNUM; j++)\n    {\n      CalTemp[i][j] = EEPROM.readUShort(ADDR_CAL_TEMP + i * 2 * CALNUM + j * 2);\n    }\n  }\n\n  language = EEPROM.readUChar(ADDR_LANGUAGE);\n  hand_side = EEPROM.readUChar(ADDR_HAND_SIDE);\n\n  return true;\n}\n\nbool update_default_temp_EEPROM()\n{\n  Serial.println(\"Updating default temp in EEPROM\");\n\n  EEPROM.writeUShort(ADDR_DEFAULT_TEMP, DefaultTemp);\n\n  if (EEPROM.commit())\n  {\n    Serial.println(\"Default temp Update Done\");\n    return true;\n  }\n  else\n  {\n    Serial.println(\"Default temp Update Failed\");\n    return false;\n  }\n}\n"
  },
  {
    "path": "SolderingPen_ESP32S2/config.h",
    "content": "// Firmware version\n#define VERSION \"v4.5.3\" //20240130\n#define VERSION_NUM 422\n\n// Type of MOSFET\n#define P_MOSFET // P_MOSFET or N_MOSFET\n\n// Type of OLED Controller\n// #define SSD1306\n#define SH1107\n//typedef u8g2_uint_t u8g_uint_t;\n#define SCREEN_OFFSET     2\n\n// 旋转编码器的类型\n#define ROTARY_TYPE       0     // 0: 2 increments/step; 1: 4 increments/step (default)\n#define BUTTON_DELAY      5\n\n// Pins\n#define SENSOR_PIN        1     // tip temperature sense 烙铁头温感\n#define VIN_PIN           6     // input voltage sense 检测输入电压\n#define BUZZER_PIN        3     // buzzer 蜂鸣器\n#define BUTTON_PIN        0     // switch 按键right\n#define BUTTON_P_PIN      4     // 1 键位为“+”\n#define BUTTON_N_PIN      2     // 2 键位为“-”\n#define CONTROL_PIN       5     // heater MOSFET PWM control 加热器MOSFET PWM控制\n#define CONTROL_CHANNEL   2     // PWM channel\n#define CONTROL_FREQ      200   // PWM frequency\n#define CONTROL_FREQ_20V  1000  // PWM frequency for 20V\n#define CONTROL_RES       8     // PWM resolution\n\n#define PD_CFG_0          16\n#define PD_CFG_1          17\n#define PD_CFG_2          18\n\n// 默认温度控制值(推荐焊接温度:300~380°C)\n#define TEMP_MIN          50    // 最小温度\n#define TEMP_MAX          450   // 最大温度\n#define TEMP_DEFAULT      260   // 默认温度\n#define TEMP_SLEEP        150   // 休眠温度\n#define TEMP_BOOST        50    // 升温步进\n#define TEMP_STEP         10    // 旋转编码器温度变化步进\n#define POWER_LIMIT_15    170   // 功率限制\n#define POWER_LIMIT_20    255   // 功率限制\n#define POWER_LIMIT_20_2  127   // 功率限制\n\n// 默认的T12烙铁头温度校准值\n#define TEMP200           200   // temperature at ADC = 200 \n#define TEMP280           280   // temperature at ADC = 280\n#define TEMP360           360   // temperature at ADC = 360 \n#define TEMPCHP           35    // chip temperature while calibration 校准时芯片温度\n#define CALNUM            4     // Calibration point number\n#define TIPMAX            8     // max number of tips\n#define TIPNAMELENGTH     6     // max length of tip names (including termination)\n#define TIPNAME           \"PTS  \" // default tip name\n\n// 默认的定时器值 (0 = 禁用)\n#define TIME2SLEEP        60    // 几秒钟后进入睡眠模式\n#define TIME2OFF          5     // 几分钟后就要关闭加热器了\n#define TIMEOFBOOST       60    // 停留在加热模式多少秒\n#define WAKEUP_THRESHOLD  10    // MPU 震动检测精度，数值越小，越灵敏\n\n// Control values\n#define TIME2SETTLE       5000  // 以微秒为单位的时间允许OpAmp输出稳定\n#define TIME2SETTLE_20V   2000  // 以微秒为单位的时间允许OpAmp输出稳定\n#define SMOOTHIE          0.05  // OpAmp输出平滑系数 (1=无平滑; 默认：0.05)\n#define PID_ENABLE        false // enable PID control\n#define BEEP_ENABLE       true  // enable/disable buzzer\n#define VOLTAGE_VALUE     3     // 电压值\n#define QC_ENABLE         false // enable/disable QC3.0\n#define MAINSCREEN        1     // type of main screen (0: big numbers; 1: more infos)\n\n// EEPROM identifier\n#define EEPROM_SIZE       1024\n\n// MOSFET control definitions\n#if defined(P_MOSFET)           // P-Channel MOSFET\n#define HEATER_ON         255\n#define HEATER_OFF        0\n#define HEATER_PWM        255 - Output\n#elif defined(N_MOSFET)         // N-Channel MOSFET\n#define HEATER_ON         0\n#define HEATER_OFF        255\n#define HEATER_PWM        Output\n#else\n#error Wrong MOSFET type!\n#endif\n\n//Language\n#define DEFAULT_LANGUAGE  0\n\n//Hand side\n#define DEFAULT_HAND_SIDE 1\n"
  },
  {
    "path": "boards/PTS200.json",
    "content": "{\n    \"build\": {\n      \"arduino\": {\n        \"ldscript\": \"esp32s2_out.ld\"\n      },\n      \"core\": \"esp32\",\n      \"extra_flags\": [\n        \"-DARDUINO_USB_CDC_ON_BOOT=1\"\n      ],\n      \"f_cpu\": \"240000000L\",\n      \"f_flash\": \"80000000L\",\n      \"flash_mode\": \"qio\",\n      \"hwids\": [\n        [\n          \"0X303A\",\n          \"0x80C5\"\n        ]\n      ],\n      \"mcu\": \"esp32s2\",\n      \"variant\": \"esp32s2\"\n    },\n    \"debug\": {\n      \"openocd_board\": \"esp32s2.cfg\"\n    },\n    \"frameworks\": [\n      \"arduino\",\n      \"espidf\"\n    ],\n    \"name\": \"Songguo PTS200\",\n    \"upload\": {\n      \"flash_size\": \"4MB\",\n      \"maximum_ram_size\": 327680,\n      \"maximum_size\": 4194304,\n      \"use_1200bps_touch\": true,\n      \"wait_for_upload_port\": true,\n      \"require_upload_port\": true,\n      \"speed\": 921600\n    },\n    \"url\": \"https://github.com/Eddddddddy/Songguo-PTS200\",\n    \"vendor\": \"Eddy\"\n  }\n  "
  },
  {
    "path": "docs/update_guide.md",
    "content": "Please use the user version for regular upgrades. Connect the device to the computer with a USB cable, open the firmware upgrade option in the device's menu, and drag the firmware file into the device's MSC storage.\n\nIf there is an upgrade failure or other problems with the firmware, you can use the factory version of the firmware and use the ESP flash tool to write the firmware at address 0x0000. Select ESP32S2-Develop-Internal USB to download."
  },
  {
    "path": "platformio.ini",
    "content": "; PlatformIO Project Configuration File\n;\n;   Build options: build flags, source filter\n;   Upload options: custom upload port, speed and extra flags\n;   Library options: dependencies, extra library storages\n;   Advanced options: extra scripting\n;\n; Please visit documentation for the other options and examples\n; https://docs.platformio.org/page/projectconf.html\n\n[platformio]\nsrc_dir = SolderingPen_ESP32S2\n\n[env:solderingpen]\nplatform = espressif32\nboard = PTS200\nframework = arduino\nlib_deps =\n  lennarthennigs/Button2 @ ^2.2.2\n  vdeconinck/QC3Control @ ^1.4.1\n  olikraus/U8g2 @ ^2.34.17\n  madhephaestus/ESP32AnalogRead @ ^0.2.1\n  br3ttb/PID @ ^1.2.1\n  sparkfun/SparkFun LIS2DH12 Arduino Library @ ^1.0.3\n"
  }
]