<template>
  <div class="container">
    <Breadcrumb :items="['指南', '使用117P6版']" />
    <a-row :gutter="20" align="stretch">
      <a-col :span="24">
        <a-card class="general-card" title="使用117P6版">
          <a-steps :current="state.step">
            <a-step>选择固件类型</a-step>
            <a-step>使用自定义固件</a-step>
            <a-step>完成</a-step>
          </a-steps>
          <a-divider/>
          <div v-show="state.step == 1" style="min-height: 300px; margin: 50px;">
            <p style="font-size: 1.2em; font-weight: bold;">你是否想要扩容你的设备以支持中文信道存储:</p>
            <a-radio-group type="button" v-model="state.kIt">
              <a-radio value="yes">是的,我想要硬件改造我的设备</a-radio>
              <a-radio value="no">不,我不需要中文信道</a-radio>
            </a-radio-group>
            <br>
            <div v-show="state.kIt == 'yes'">
              <p style="color: #ff0000; font-weight: bold;">声明:本方案及相应固件均为技术探索用途。对原机进行改造需要相应专业知识且可能存在安全和法律风险。使用本方案和固件代表您已认可风险并自行承担后果,包括且不限于财产损失、人员伤亡、违法犯罪等。</p>
              <p style="font-weight: bold; font-size: 1.2em;">一、相关法律</p>
              <p>
                自制、改装、拼装的无线电发射设备,应符合国家相关技术标准,并按照工信部官网链接(<a href="http://www.miit.gov.cn/jgsj/wgj/kpzs/art/2022/art_c1ffd3c47e3f455dad38246579092136.html" target="_blank" rel="noopener noreferrer">http://www.miit.gov.cn/jgsj/wgj/kpzs/art/2022/art_c1ffd3c47e3f455dad38246579092136.html</a>,或通过工信部官网-工业和信息化部-机关司局-无管局-科普知识-《关于申请设置、使用业余无线电台所用无线电发射设备相关事宜的说明》)所列情况,提供相应材料。
              </p>
              <p style="font-weight: bold; font-size: 1.2em;">二、所需工具</p>
              <p>
                写频线、螺丝刀套装、电烙铁、焊锡丝、助焊剂、精密电器清洁剂(可选)、撬棒(可选)、万用表(可选)。
              </p>
              <p style="font-weight: bold; font-size: 1.2em;">三、购买扩容芯片</p>
              <p>芯片型号:<span style="color: #ff0000;">M24M02-DRMN6</span> 或其它 SOP-8 封装 I²C 总线 2Mbit EEPROM 芯片。考虑到芯片质量及操作失误可能导致的损坏,建议多买几片备用。</p>
              <p>
                该教程由 BH3RVG 火星人整理提供。 
              </p>
            </div>
            <div v-show="state.kIt == 'no'">
              <p style="color: #ff0000; font-weight: bold;">声明:本方案及相应固件均为技术探索用途。对原机进行改造需要相应专业知识且可能存在安全和法律风险。使用本方案和固件代表您已认可风险并自行承担后果,包括且不限于财产损失、人员伤亡、违法犯罪等。</p>
              <p style="font-weight: bold; font-size: 1.2em;">一、所需工具</p>
              <p>
                写频线。
              </p>
              <p>
                该教程由 BH3RVG 火星人整理提供。 
              </p>
            </div>
          </div>
          <div v-show="state.step == 1" style="text-align: center;">
            <a-button type="primary" :disabled="!state.kIt" @click="state.step = 2">下一步</a-button>
          </div>
          <div v-show="state.step == 2" style="min-height: 300px; text-align: center; color: #C9CDD4; ">
            <a-spin :loading="state.loading" tip="处理中..." style="width: 100%;">
              <a-collapse :activeKey="state.flashStep" @change="(e: any)=>{state.flashStep = e; if(e[0] == 'six'){state.finish = true;}}" accordion>
                <a-collapse-item header="备份原机数据" key="one">
                  <div style="text-align: left;">
                    <p>在对设备进行操作前,应备份原机出厂的配置、校准数据,以保证发射性能符合国家标准。(请妥善保存备份文件)</p>
                    <p>
                      <a-space>
                        <a-button type="primary" :disabled="state.backed" @click="backupIt">备份</a-button><span v-show="state.backed" style="color: #C9CDD4;">已备份✔</span>&nbsp;
                        <a-button type="primary" :disabled="!state.backed" @click="state.kIt == 'yes' ? state.flashStep[0] = 'two' : state.flashStep[0] = 'three'">下一步</a-button>
                      </a-space>
                    </p>
                  </div>
                </a-collapse-item>
                <a-collapse-item v-show="state.kIt == 'yes'" header="拆机" key="two">
                  <div style="text-align: left;">
                    <p>视频教程链接:
                      <a href="https://www.bilibili.com/video/BV1ib4y137Ah" target="_blank" rel="noopener noreferrer">https://www.bilibili.com/video/BV1ib4y137Ah</a>
                      <span style="color: #ff0000;">(硬件拆解及焊接部分可参照本视频,软件刷机部分请务必以本指南为准。)</span>
                    </p>
                    <div>
                      ①拆掉电池、天线和旋钮盖。<br>
                      ②用撬棒插入主机背面底部正中位置缝隙,向上撬出铝制背板。③向下后方抽出背板。前盖和主板间有扬声器导线连接,此处用力不要过猛,控制幅度,以免拉断导线。<br>
                      ④拿掉耳机口挡板。<br>
                      ⑤建议将扬声器导线拆焊,以免阻碍后续拆解和焊接,导致拉断导线。最后组装时再对扬声器导线进行焊接。<br>
                      ⑥拆卸屏幕(难点,请认真看视频教程!)。在屏幕左下角卡扣位置,用撬棒向内按压同时向上抬起即可拆卸左侧,屏幕左侧松脱后另一侧拆卸相对简单。此处用力不要过猛,控制幅度,屏幕完全拆卸后应妥善固定,以免拉断、折断背面上方排线。<br>
                      ⑦拆卸全部 5 颗螺丝并分离背板。
                    </div>
                    <img :src="cj1">
                    <div>
                      需要更换的芯片位于主板背面右下角,型号为 BL24C64A。
                    </div>
                    <img :src="cj2">
                    <div>
                      ①拆焊及焊接。有动手能力的朋友自行操作,要求芯片方向正确(以第1 脚圆点为准),焊点饱满,无虚焊、短路,芯片周围的电子元器件保持完好。建议用300℃以上小刀头烙铁配合助焊剂,不建议用热风枪(高手除外)。手残党可以去手机维修店更换,费用5-30 元不等。若周围元件遭到破坏,可按下图参数更换补救。
                    </div>
                    <img :src="cj3">
                    <div>
                      ②将主板装回背板。(背板上 3x5mm 导热硅胶垫若脱落,请务必装回对应凸起位置;电池触点部分过背板孔时当心压弯。)<br>
                      ③装入电池,按住 PTT 键开机,进入刷机模式(此时手电筒常亮、屏幕无显示)。如无法进入刷机模式,检查电池接触片是否错位、焊点及周边元件是否完好。
                    </div>
                    <div style="color: #ff0000; font-weight: bold;">
                      此时先不要完全组装手台,待后续工作全部完成后再行组装,以便故障返工。此阶段如尝试正常开机后显示异常、电量异常、接收异常等均为正常情况,不用担心。后续操作后会恢复正常。
                    </div>
                    <div>
                      <a-button type="primary" @click="state.flashStep[0] = 'three'">下一步</a-button>
                    </div>
                  </div>
                </a-collapse-item>
                <a-collapse-item header="刷入固件" key="three">
                  <div style="text-align: left;">
                    <p>断开写频线,按住 PTT 键开机,进入刷机模式(此时手电筒常亮、屏幕无显示),手电筒常亮后插回写频线。</p>
                    <p>
                      <a-space>
                        <a-button type="primary" :disabled="state.flashIt" @click="iFlashIt">刷入固件</a-button>
                        <a-button type="primary" :disabled="!state.flashIt" @click="state.kIt == 'yes' ? state.flashStep[0] = 'four' : finishIt()">下一步</a-button>
                      </a-space>
                    </p>
                  </div>
                </a-collapse-item>
                <a-collapse-item v-show="state.kIt == 'yes'" header="刷回原机数据" key="four">
                  <div style="text-align: left;">
                    <p>正常开机,使设备处于开机状态,点击刷回备份数据。</p>
                    <p>
                      <a-space>
                        <a-button type="primary" :disabled="state.restoreBackupIt" @click="restoreBackup">刷回备份数据</a-button>
                        <a-button type="primary" :disabled="!state.restoreBackupIt" @click="state.flashStep[0] = 'five'">下一步</a-button>
                      </a-space>
                    </p>
                  </div>
                </a-collapse-item>
                <a-collapse-item v-show="state.kIt == 'yes'" header="刷入字库" key="five">
                  <div style="text-align: left;">
                    <p>正常开机,使设备处于开机状态,点击刷入字库。</p>
                    <p>
                      <a-space>
                        <a-button type="primary" :disabled="state.flashFontIt" @click="flashFont">刷入字库</a-button>
                        <a-button type="primary" :disabled="!state.flashFontIt" @click="finishIt">下一步</a-button>
                      </a-space>
                    </p>
                  </div>
                </a-collapse-item>
                <a-collapse-item header="完全组装" key="six">
                  <div style="text-align: left;">如果扩容,按拆解顺序进行焊接和组装。</div>
                </a-collapse-item>
              </a-collapse>
            </a-spin>
          </div>
          <div v-show="state.step == 2" style="text-align: center;">
            <a-space>
              <a-button @click="state.step = 1">上一步</a-button>
              <a-button type="primary" :disabled="!state.finish" @click="state.step = 3">完成</a-button>
            </a-space>
          </div>
          <div v-show="state.step == 3" style="min-height: 300px; text-align: center; color: #C9CDD4; ">
            <a-result
              class="result"
              status="success"
              subtitle="刷入成功"
            />
            <a-button type="primary" @click="()=>{router.push('/chirp/base');}">
              返回首页
            </a-button>
          </div>
        </a-card>
      </a-col>
    </a-row>
  </div>
</template>

<script lang="ts" setup>
import { reactive, nextTick } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { useAppStore } from '@/store';
import { eeprom_write, eeprom_reboot, eeprom_init, eeprom_read, flash_flashFirmware, connect, disconnect, sendPacket, unpackVersion, readPacket, unpack } from '@/utils/serial.js';
import cj1 from './assets/cj1.png'
import cj2 from './assets/cj2.png'
import cj3 from './assets/cj3.png'

const appStore = useAppStore();
const router = useRouter();

const state : {
  step: any,
  flashStep: any,
  backed: any,
  kIt: any,
  flashIt: any,
  restoreBackupIt: any,
  loading: any,
  flashFontIt: any,
  finish: any
} = reactive({
  step: 1,
  flashStep: ['one'],
  backed: undefined,
  kIt: undefined,
  flashIt: false,
  restoreBackupIt: false,
  loading: false,
  flashFontIt: false,
  finish: false
})

const backupRange = async (start: any, end: any, name: any = new Date() + '_backup.bin') =>{
  await eeprom_init(appStore.connectPort);
  let rawEEPROM = new Uint8Array(end - start);
  for (let i = start; i < end; i += 0x40) {
    const data = await eeprom_read(appStore.connectPort, i, 0x40, appStore.configuration?.uart);
    rawEEPROM.set(data, i - start);
  }
  const blob = new Blob([rawEEPROM], { type: 'application/octet-stream' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = name;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
  return rawEEPROM;
}

const restoreRange = async (start: any = 0, uint8Array: any) => {
  await eeprom_init(appStore.connectPort);
  for (let i = start; i < uint8Array.length + start; i += 0x40) {
    await eeprom_write(appStore.connectPort, i, uint8Array.slice(i - start, i - start + 0x40), uint8Array.slice(i - start, i - start + 0x40).length, appStore.configuration?.uart);
  }
  await eeprom_reboot(appStore.connectPort);
}

const finishIt = () => {
  state.flashStep[0] = 'six'
  state.finish = true
}

const backupIt = async () => {
  if(appStore.connectState != true){alert('点击右上角“连接”按钮连接手台。'); return;};
  state.loading = true
  state.backed = await backupRange(0, 0x2000);
  console.log(state.backed)
  state.loading = false
}

const iFlashIt = async () => {
  state.loading = true
  let fontPacket = undefined
  if(state.kIt == 'yes'){
    fontPacket = await fetch('/LOSEHU117P6K.bin')
  }else{
    fontPacket = await fetch('/LOSEHU117P6.bin')
  }
  const reader = fontPacket.body.getReader();
  const chunks = [];
  while(true) {
    const {done, value} = await reader.read();
    if (done) {
      break;
    }
    chunks.push(...value)
  }
  const binary = new Uint8Array(chunks)
  if(appStore.connectPort){
    await disconnect(appStore.connectPort);
  }
  let _connect = await connect();
  await readPacket(_connect, 0x18, 1000);
  const rawVersion = unpackVersion(binary);
  const _data = new Uint8Array([0x30, 0x5, rawVersion.length, 0x0, ...rawVersion]);
  await sendPacket(_connect, _data);
  await readPacket(_connect, 0x18)
  await flash_flashFirmware(_connect, unpack(binary))
  appStore.updateSettings({ connectPort: _connect });
  state.flashIt = true
  state.loading = false
}

const restoreBackup = async () => {
  if(appStore.connectState != true){alert('点击右上角“连接”按钮连接手台。'); return;};
  state.loading = true
  await restoreRange(0, state.backed);
  state.restoreBackupIt = true;
  state.loading = false
}

const flashFont = async () => {
  state.loading = true
  const fontPacket = await fetch('/old_font.bin')
  const reader = fontPacket.body.getReader();
  const chunks = [];
  while(true) {
    const {done, value} = await reader.read();
    if (done) {
      break;
    }
    chunks.push(...value)
  }
  const binary = new Uint8Array(chunks)
  await restoreRange(0x02000, binary)
  state.flashFontIt = true;
  state.loading = false
}

</script>

<script lang="ts">
  export default {
    name: 'Chi',
  };
</script>

<style scoped lang="less">
  .container {
    padding: 0 20px 20px 20px;
    :deep(.arco-list-content) {
      overflow-x: hidden;
    }

    :deep(.arco-card-meta-title) {
      font-size: 14px;
    }
  }
  :deep(.arco-list-col) {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: space-between;
  }

  :deep(.arco-list-item) {
    width: 33%;
  }

  :deep(.block-title) {
    margin: 0 0 12px 0;
    font-size: 14px;
  }
  :deep(.list-wrap) {
    // min-height: 140px;
    .list-row {
      align-items: stretch;
      .list-col {
        margin-bottom: 16px;
      }
    }
    :deep(.arco-space) {
      width: 100%;
      .arco-space-item {
        &:last-child {
          flex: 1;
        }
      }
    }
  }
</style>