diff --git a/src/views/list/sat/index.vue b/src/views/list/sat/index.vue index e1012c7..f22f60e 100644 --- a/src/views/list/sat/index.vue +++ b/src/views/list/sat/index.vue @@ -5,54 +5,57 @@ <a-col :span="24"> <a-card class="general-card" title="卫星写入"> <a-spin :loading="loading" style="width: 100%;" tip="正在处理 ..."> - <a-form-item :label-col-style="{width: '25%'}" field="sat" label="选择卫星"> + <a-form-item :label-col-style="{ width: '25%' }" field="sat" label="选择卫星"> <a-select v-model="state.sat" @change="changeSat" placeholder="选择卫星 ..." allow-search allow-clear> - <a-option v-for="item in state.satData" :key="item.name" :value="item.name">{{item.name}}</a-option> + <a-option v-for="item in state.satData" :key="item.name" :value="item.name">{{ item.name }}</a-option> </a-select> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" field="lng" label="台站经度"> + <a-form-item :label-col-style="{ width: '25%' }" field="lng" label="台站经度"> <a-input-number :precision="6" v-model="state.lng" /> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" field="lat" label="台站纬度"> + <a-form-item :label-col-style="{ width: '25%' }" field="lat" label="台站纬度"> <a-input-number :precision="6" v-model="state.lat" /> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" field="alt" label="台站海拔"> + <a-form-item :label-col-style="{ width: '25%' }" field="alt" label="台站海拔"> <a-input-number :precision="0" v-model="state.alt" /> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" label=""> + <a-form-item :label-col-style="{ width: '25%' }" label=""> <a-space> <a-button @click="getLocation">浏览器获取经纬度</a-button> <a-button @click="getPass">获取卫星过境时间</a-button> </a-space> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" field="pass" label="选择过境时间"> + <a-form-item :label-col-style="{ width: '25%' }" field="pass" label="选择过境时间"> <a-select v-model="state.pass" allow-search allow-clear> - <a-option v-for="item in state.passOption" :key="item[0] + '|' + item[1]" :value="item[0] + '|' + item[1]">{{item[0] + " - " + item[1]}}</a-option> + <a-option v-for="item in state.passOption" :key="item[0] + '|' + item[1]" + :value="item[0] + '|' + item[1]">{{ item[0] + " - " + item[1] }}</a-option> </a-select> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" field="tx" label="上行频率"> + <a-form-item :label-col-style="{ width: '25%' }" field="tx" label="上行频率"> <a-input-number :precision="5" v-model="state.tx" /> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" field="txTone" label="上行亚音"> + <a-form-item :label-col-style="{ width: '25%' }" field="txTone" label="上行亚音"> <a-select v-model="state.txTone" allow-search allow-clear> <a-option :value="0">关闭</a-option> - <a-option v-for="item in state.CTCSSOption" :key="item" :value="item">{{item.toFixed(1)}}</a-option> + <a-option v-for="item in state.CTCSSOption" :key="item" :value="item">{{ item.toFixed(1) }}</a-option> </a-select> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" field="rx" label="下行频率"> + <a-form-item :label-col-style="{ width: '25%' }" field="rx" label="下行频率"> <a-input-number :precision="5" v-model="state.rx" /> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" field="rxTone" label="下行亚音"> + <a-form-item :label-col-style="{ width: '25%' }" field="rxTone" label="下行亚音"> <a-select v-model="state.rxTone" allow-search allow-clear> <a-option :value="0">关闭</a-option> - <a-option v-for="item in state.CTCSSOption" :key="item" :value="item">{{item.toFixed(1)}}</a-option> + <a-option v-for="item in state.CTCSSOption" :key="item" :value="item">{{ item.toFixed(1) }}</a-option> </a-select> </a-form-item> - <a-form-item :label-col-style="{width: '25%'}" label=""> + <a-form-item :label-col-style="{ width: '25%' }" label=""> <a-button @click="writeIt">写入数据</a-button> </a-form-item> <a-divider /> - <div id="statusArea" style="height: 20em; background-color: azure; color: silver; overflow: auto; padding: 20px" v-html="state.status"></div> + <div id="statusArea" + style="height: 20em; background-color: azure; color: silver; overflow: auto; padding: 20px" + v-html="state.status"></div> </a-spin> </a-card> </a-col> @@ -63,14 +66,14 @@ <script lang="ts" setup> import { reactive, nextTick } from 'vue'; import { useAppStore } from '@/store'; -import { eeprom_write, eeprom_reboot, eeprom_init } from '@/utils/serial.js'; +import { eeprom_write, eeprom_reboot, eeprom_init, hexReverseStringToUint8Array, stringToUint8Array } from '@/utils/serial.js'; import useLoading from '@/hooks/loading'; const { loading, setLoading } = useLoading(true); const appStore = useAppStore(); -const state : { +const state: { status: string, sat: string, satData: any[], @@ -107,16 +110,16 @@ const state : { }) const changeSat = async (sat: any) => { - const data = state.satData.find(e=>e.name == sat); - if(data && data.path){ + const data = state.satData.find(e => e.name == sat); + if (data && data.path) { state.status += '<br/>卫星参数:<br/>' - data.path.map((e:string)=>{ + data.path.map((e: string) => { state.status += e + '<br/>' }) } - nextTick(()=>{ + nextTick(() => { const textarea = document?.getElementById('statusArea'); - if(textarea)textarea.scrollTop = textarea?.scrollHeight; + if (textarea) textarea.scrollTop = textarea?.scrollHeight; }) } @@ -125,16 +128,16 @@ const initSat = async () => { const rst = await (await fetch('https://celestrak.org/NORAD/elements/amateur.txt')).text() const lines = rst.split(/\r?\n/); const sat = []; - let _sat:any = {}; - for(let i = 0; i < lines.length; i++){ - if(Number.isNaN(parseInt(lines[i].substring(0, 1)))){ - if(_sat.name && _sat.name != ''){ + let _sat: any = {}; + for (let i = 0; i < lines.length; i++) { + if (Number.isNaN(parseInt(lines[i].substring(0, 1)))) { + if (_sat.name && _sat.name != '') { sat.push(_sat) _sat = {} } _sat.name = lines[i] - }else{ - if(!_sat.path){_sat.path = []} + } else { + if (!_sat.path) { _sat.path = [] } _sat.path.push(lines[i]) } } @@ -144,11 +147,11 @@ const initSat = async () => { initSat() const getLocation = async () => { setLoading(true) - navigator.geolocation.getCurrentPosition((e)=>{ - if(e.coords){ + navigator.geolocation.getCurrentPosition((e) => { + if (e.coords) { state.lat = e.coords.latitude state.lng = e.coords.longitude - if(e.coords.altitude)state.alt = e.coords.altitude + if (e.coords.altitude) state.alt = e.coords.altitude } }); setLoading(false) @@ -160,9 +163,9 @@ const restoreRange = async (start: any = 0, uint8Array: any) => { for (let i = start; i < uint8Array.length + start; i += 0x80) { await eeprom_write(appStore.connectPort, i, uint8Array.slice(i - start, i - start + 0x80), 0x80, appStore.configuration?.uart); state.status = state.status + "写入进度:" + (((i - start) / uint8Array.length) * 100).toFixed(1) + "%<br/>"; - nextTick(()=>{ + nextTick(() => { const textarea = document?.getElementById('statusArea'); - if(textarea)textarea.scrollTop = textarea?.scrollHeight; + if (textarea) textarea.scrollTop = textarea?.scrollHeight; }) } state.status = state.status + "写入进度:100.0%<br/>"; @@ -170,7 +173,7 @@ const restoreRange = async (start: any = 0, uint8Array: any) => { } const getPass = async () => { - if(!state.sat){alert('请选择卫星!'); return;}; + if (!state.sat) { alert('请选择卫星!'); return; }; setLoading(true) const res = await (await fetch('https://k5.vicicode.com/api/pass', { method: "POST", @@ -180,34 +183,41 @@ const getPass = async () => { }, body: JSON.stringify({ sat: state.sat, - sat_line_1: state.satData.find(e=>e.name == state.sat).path[0], - sat_line_2: state.satData.find(e=>e.name == state.sat).path[1], + sat_line_1: state.satData.find(e => e.name == state.sat).path[0], + sat_line_2: state.satData.find(e => e.name == state.sat).path[1], lat: state.lat, lng: state.lng, alt: state.alt }) })).json() const passOption = [] - for(let i=0; i<res.pass_times.length; i++){ - const _passOption = [res.pass_times[i], res.departure_times[i]] - passOption.push(_passOption) + for (let i = 0; i < res.pass_times.length; i++) { + try{ + let _passOption = undefined + if((Date.parse(res.departure_times[i]) - Date.parse(res.pass_times[i])) > 0){ + _passOption = [res.pass_times[i], res.departure_times[i]] + }else{ + _passOption = [res.pass_times[i], res.departure_times[i + 1]] + } + passOption.push(_passOption) + }catch{} } - if(passOption.length > 0){ + if (passOption.length > 0) { state.pass = passOption[0][0] + "|" + passOption[0][1] - }else{ + } else { state.pass = undefined } state.passOption = passOption setLoading(false) } -const writeIt = async() => { - if(appStore.connectState != true){alert('请先连接手台!'); return;}; +const writeIt = async () => { + if (appStore.connectState != true) { alert('请先连接手台!'); return; }; // if(appStore.configuration?.sat != true){ // alert('固件版本不匹配'); // return; // } - if(!state.pass){alert('请选择过境时间!'); return;}; + if (!state.pass) { alert('请选择过境时间!'); return; }; setLoading(true) const res = await (await fetch('https://k5.vicicode.com/api/doppler', { method: "POST", @@ -217,8 +227,8 @@ const writeIt = async() => { }, body: JSON.stringify({ sat: state.sat, - sat_line_1: state.satData.find(e=>e.name == state.sat).path[0], - sat_line_2: state.satData.find(e=>e.name == state.sat).path[1], + sat_line_1: state.satData.find(e => e.name == state.sat).path[0], + sat_line_2: state.satData.find(e => e.name == state.sat).path[1], lat: state.lat, lng: state.lng, alt: state.alt, @@ -228,62 +238,131 @@ const writeIt = async() => { departure_time: state.pass.split('|')[1] }) })).json() - state.status += JSON.stringify(res.shift_array) + '<br/>' - nextTick(()=>{ - const textarea = document?.getElementById('statusArea'); - if(textarea)textarea.scrollTop = textarea?.scrollHeight; + + const sat = state.sat + const pass = state.pass.split('|')[0] + const pass_year = pass.split('-')[0].substring(2, 4) + const pass_month = pass.split('-')[1] + const pass_day = pass.split('-')[2].split(' ')[0] + const pass_hour = pass.split(' ')[1].split(':')[0] + const pass_min = pass.split(' ')[1].split(':')[1] + const pass_sec = pass.split(' ')[1].split(':')[2] + const departure = state.pass.split('|')[1] + const departure_year = departure.split('-')[0].substring(2, 4) + const departure_month = departure.split('-')[1] + const departure_day = departure.split('-')[2].split(' ')[0] + const departure_hour = departure.split(' ')[1].split(':')[0] + const departure_min = departure.split(' ')[1].split(':')[1] + const departure_sec = departure.split(' ')[1].split(':')[2] + // console.log(sat.trim(), new Date(pass), pass_year, pass_month, pass_day, pass_hour, pass_min, pass_sec) + // console.log(sat.trim(), new Date(departure), departure_year, departure_month, departure_day, departure_hour, departure_min, departure_sec) + + await eeprom_init(appStore.connectPort); + // 卫星名称 + let payload = new Uint8Array(10) + payload.set(stringToUint8Array(sat.trim()).subarray(0, 9)) + await eeprom_write(appStore.connectPort, 0x2BA0, payload, 10, appStore.configuration?.uart); + // 写入过境始末 + await eeprom_write(appStore.connectPort, 0x2BAA, hexReverseStringToUint8Array(parseInt(pass_year).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BAB, hexReverseStringToUint8Array(parseInt(pass_month).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BAC, hexReverseStringToUint8Array(parseInt(pass_day).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BAD, hexReverseStringToUint8Array(parseInt(pass_hour).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BAE, hexReverseStringToUint8Array(parseInt(pass_min).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BAF, hexReverseStringToUint8Array(parseInt(pass_sec).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BB0, hexReverseStringToUint8Array(parseInt(departure_year).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BB1, hexReverseStringToUint8Array(parseInt(departure_month).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BB2, hexReverseStringToUint8Array(parseInt(departure_day).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BB3, hexReverseStringToUint8Array(parseInt(departure_hour).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BB4, hexReverseStringToUint8Array(parseInt(departure_min).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + await eeprom_write(appStore.connectPort, 0x2BB5, hexReverseStringToUint8Array(parseInt(departure_sec).toString(16)).subarray(0, 1), 0x01, appStore.configuration?.uart); + // 总过境时间 + payload = new Uint8Array(2) + payload.set(hexReverseStringToUint8Array(((Date.parse(departure) - Date.parse(pass)) / 1000).toString(16)).subarray(0, 0x02)) + await eeprom_write(appStore.connectPort, 0x2BB6, payload, 0x02, appStore.configuration?.uart); + // 手台的发射接收亚音 + payload = new Uint8Array(2) + if(state.txTone && state.txTone > 0){ + payload.set(hexReverseStringToUint8Array(state.txTone.toString(16)).subarray(0, 0x02)) + } + await eeprom_write(appStore.connectPort, 0x2BB8, payload, 0x02, appStore.configuration?.uart); + payload = new Uint8Array(2) + if(state.rxTone && state.rxTone > 0){ + payload.set(hexReverseStringToUint8Array(state.rxTone.toString(16)).subarray(0, 0x02)) + } + await eeprom_write(appStore.connectPort, 0x2BBA, payload, 0x02, appStore.configuration?.uart); + // 开始过境时间的UNIX时间戳与2000年1月1日UNIX时间戳的差 + payload = new Uint8Array(4) + payload.set(hexReverseStringToUint8Array(((Date.parse(pass) - Date.parse('2000-01-01 00:00:00')) / 1000).toString(16)).subarray(0, 0x04)) + await eeprom_write(appStore.connectPort, 0x2BBC, payload, 0x04, appStore.configuration?.uart); + + const shift_arr: any = [] + res.shift_array.filter((num: any, index: any) => index % 2 === 0).map((e: any)=>{ + const _tx = new Uint8Array(4) + const _rx = new Uint8Array(4) + _tx.set(hexReverseStringToUint8Array(parseInt(((state.tx * 1000000 + e[0]) / 10).toFixed(0)).toString(16))) + _rx.set(hexReverseStringToUint8Array(parseInt(((state.rx * 1000000 + e[1]) / 10).toFixed(0)).toString(16))) + shift_arr.push(..._tx, ..._rx) }) + payload = new Uint8Array(0x1E00) + payload.set(new Uint8Array(shift_arr).subarray(0, 0x1E00)) + await restoreRange(0x1E200, payload) setLoading(false) } </script> <script lang="ts"> - export default { - name: 'Chi', - }; +export default { + name: 'Sat', +}; </script> <style scoped lang="less"> - .container { - padding: 0 20px 20px 20px; - :deep(.arco-list-content) { - overflow-x: hidden; - } +.container { + padding: 0 20px 20px 20px; - :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-content) { + overflow-x: hidden; } - :deep(.arco-list-item) { - width: 33%; - } - - :deep(.block-title) { - margin: 0 0 12px 0; + :deep(.arco-card-meta-title) { font-size: 14px; } - :deep(.list-wrap) { - // min-height: 140px; - .list-row { - align-items: stretch; - .list-col { - margin-bottom: 16px; - } +} + +: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; - } + } + + :deep(.arco-space) { + width: 100%; + + .arco-space-item { + &:last-child { + flex: 1; } } } -</style> +}</style>