Compare commits

...

38 Commits

Author SHA1 Message Date
Roy_01 bfc347ab4e feat: update PELv3.0 config table 2025-08-29 17:36:48 +08:00
Roy_01 6c9cb65d28 feat: new PELv2.0 config table 2025-08-29 17:31:42 +08:00
Roy_01 e980207645 feat: update PELv3.0 CSV column headers 2025-08-29 09:04:39 +08:00
peterlu14 3508caede2 Add PEL3.0 lib 2025-08-25 13:25:29 +08:00
peterlu14 edc9b67e0a Remove unnecessary stop instruction for PEL devices in TaskDeviceListNew component 2025-03-14 11:57:32 +08:00
peterlu14 a89ac32e9c Refactor channel handling in DownloadOffline component to filter and sort channels based on order 2025-03-14 11:57:19 +08:00
peterlu14 8522c20383 Enhance R-external calibration configuration by updating channel parameters, units, and adding new output variables 2025-03-12 16:49:01 +08:00
peterlu14 197dc3cefc Add R-external calibration configuration and integrate into PEL module 2025-03-12 15:40:20 +08:00
peterlu14 e110da9bce Refactor download actions and update channel handling in PEL configuration 2025-03-12 14:57:17 +08:00
peterlu14 f86407f8e6 Update device stop delay and enhance key event handling in PEL components 2025-02-17 15:54:52 +08:00
peterlu14 679750613c Fix condition check for device configuration mode and update formula implementation in PEL configurations 2025-02-06 17:59:03 +08:00
peterlu14 6838a54088 Rename ScanMode to IOPH and add new IOPL configuration; update device mode checks in TaskDeviceListNew 2025-02-06 15:07:23 +08:00
peterlu14 6ab5dd8f99 Add device status check before handling Enter key events in PEL component 2025-02-05 16:47:10 +08:00
peterlu14 97fed46124 Add formula support for ∆VO in ScanMode configuration 2025-02-05 15:11:55 +08:00
peterlu14 d0df337b7b Refactor quickstart method to support asynchronous archive settings and add stop instruction for PEL devices after a delay 2025-02-05 14:26:19 +08:00
peterlu14 621ae30fab Add formula support for ∆VO and update order for resistor parameters in PEL configuration 2025-02-05 13:18:18 +08:00
peterlu14 8146e53dcc Add input handling for PULSE and PATTERN with Enter key support in PEL component 2025-01-23 14:24:01 +08:00
peterlu14 fa2f45dbce Add PEL_1 component and integrate into DeviceParameterRecording.vue; introduce ScanMode configuration 2025-01-23 14:22:06 +08:00
peterlu14 eb686c7a11 Enhance PEL device support and refactor related components 2024-12-27 17:46:16 +08:00
peterlu14 27c1dc6044 Refactor device library check in TaskDeviceListNew.vue 2024-10-01 15:07:03 +08:00
peterlu14 49458ab441 Refactor device library check in TaskDeviceListNew.vue 2024-10-01 11:51:51 +08:00
peterlu14 07ba97c1b0 - Fixed CPG DevMode 2024-09-20 09:48:25 +08:00
peterlu14 1f377b7a0a - Fix text color 2024-09-12 11:35:51 +08:00
peterlu14 9a80d7eceb - Change the timer continuous mode logic 2024-09-12 11:25:53 +08:00
peterlu14 74d64c1234 - Add Info Image
- Fix timer spelling error
2024-09-12 10:55:22 +08:00
peterlu14 0eb35f35ec - Change Pattern mode UI space-evenly 2024-09-12 10:15:44 +08:00
peterlu14 7073734c0d - Fix support font Inter
- Description Eletrical Stimulation add space
- Timer modal add time unit replace placeholder
- Add cursor: pointer & change font-size
- Device name change
2024-09-11 16:45:52 +08:00
peterlu14 23d68aa880 -Add assets 2024-09-11 10:30:10 +08:00
peterlu14 6098d9b84c - Add Electrical Stimulation UI 2024-09-11 10:29:47 +08:00
peterlu14 a170b9ae1d - Complete CPG parameter table 2024-09-11 10:06:29 +08:00
peterlu14 ec23eff0b5 - Add mqtt broadcast "device_refresh"
- Remove the battery for CPG
- Remove the folder and fileName for CPG
- Remove collapse__body padding-x
2024-09-11 10:04:14 +08:00
peterlu14 6a9ad8d554 - Restrict textArea maxlength in 244 bytes 2024-08-21 17:43:12 +08:00
peterlu14 674a88460d -Developer Mode add textarea and support to 255 bytes 2024-08-21 14:59:22 +08:00
peterlu14 8dd8cb52e6 -Allow the CPG start button 2024-08-21 14:58:34 +08:00
peterlu14 a206479d08 - Add CPG Device with Dev Mode 2024-07-31 15:03:55 +08:00
peterlu14 a0315a4e56 - Add PEL Mode 2024-07-30 10:46:40 +08:00
Roy_01 644887a151 modify: libraryNameMappingTable add edc2.0 2024-05-09 09:51:27 +08:00
peterlu14 d7ad076dbe config add elite 2.0 2024-03-08 09:36:25 +08:00
41 changed files with 3722 additions and 91 deletions
@@ -0,0 +1,4 @@
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="13.5" cy="13.5" r="12.5" fill="#37E893" stroke="#37E893" stroke-width="2"/>
<path d="M21.5 12.634C22.1667 13.0189 22.1667 13.9811 21.5 14.366L10.25 20.8612C9.58333 21.2461 8.75 20.765 8.75 19.9952V7.00481C8.75 6.23501 9.58333 5.75388 10.25 6.13878L21.5 12.634Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 392 B

+4
View File
@@ -0,0 +1,4 @@
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="13.5" cy="13.5" r="12.5" fill="#E6E6E6" stroke="#E6E6E6" stroke-width="2"/>
<path d="M21.5 12.634C22.1667 13.0189 22.1667 13.9811 21.5 14.366L10.25 20.8612C9.58333 21.2461 8.75 20.765 8.75 19.9952V7.00481C8.75 6.23501 9.58333 5.75388 10.25 6.13878L21.5 12.634Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 392 B

@@ -0,0 +1,7 @@
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="13.5" cy="13.5" r="12.5" fill="#FF8D8D" stroke="#FF8D8D" stroke-width="2"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="15" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="15" y="7" width="4" height="13" rx="2" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 441 B

+9
View File
@@ -0,0 +1,9 @@
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="13.5" cy="13.5" r="12.5" fill="#E6E6E6" stroke="#E6E6E6" stroke-width="2"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="15" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="15" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 565 B

@@ -0,0 +1,3 @@
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 14.0833V9.74996M22.75 6.49996L20.5833 4.33329M10.8333 2.16663H15.1666M13 22.75C10.7014 22.75 8.49704 21.8369 6.87172 20.2116C5.24641 18.5862 4.33331 16.3818 4.33331 14.0833C4.33331 11.7847 5.24641 9.58035 6.87172 7.95503C8.49704 6.32972 10.7014 5.41663 13 5.41663C15.2985 5.41663 17.5029 6.32972 19.1282 7.95503C20.7536 9.58035 21.6666 11.7847 21.6666 14.0833C21.6666 16.3818 20.7536 18.5862 19.1282 20.2116C17.5029 21.8369 15.2985 22.75 13 22.75Z" stroke="#2C4052" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 648 B

+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="640.000000pt" height="320.000000pt" viewBox="0 0 1280.000000 640.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.15, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,640.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M9638 6075 c-772 -93 -1504 -467 -2317 -1184 -198 -174 -334 -303
-657 -624 -230 -229 -264 -258 -281 -249 -11 6 -100 93 -199 194 -1144 1171
-1886 1664 -2745 1822 -560 103 -1141 38 -1669 -186 -885 -376 -1533 -1167
-1714 -2093 -41 -207 -51 -318 -51 -565 0 -392 54 -719 176 -1065 338 -964
1145 -1627 2164 -1779 634 -95 1337 26 1957 335 243 121 448 250 703 441 321
239 556 450 1061 950 176 175 327 318 334 318 8 0 77 -66 154 -146 172 -179
592 -584 770 -743 820 -731 1442 -1055 2226 -1163 58 -8 194 -12 350 -12 213
0 279 4 400 23 650 100 1205 379 1659 832 457 457 742 1045 823 1699 19 155
16 563 -6 720 -78 561 -275 1067 -568 1457 -95 128 -294 332 -425 435 -364
290 -837 486 -1378 570 -172 26 -594 34 -767 13z m-6331 -1199 c336 -71 676
-233 1010 -481 119 -88 297 -234 413 -339 146 -133 880 -850 880 -860 0 -16
-640 -649 -795 -788 -492 -438 -947 -715 -1375 -839 -202 -58 -321 -74 -565
-74 -190 0 -235 3 -334 23 -590 119 -1022 504 -1210 1077 -160 489 -130 953
90 1385 252 496 706 824 1266 915 63 10 146 13 293 10 172 -3 225 -8 327 -29z
m6863 19 c327 -46 605 -171 841 -378 439 -384 649 -1063 517 -1677 -134 -625
-615 -1131 -1229 -1295 -148 -39 -279 -55 -454 -55 -310 0 -559 62 -870 215
-327 160 -642 391 -1037 761 -248 232 -743 719 -746 734 -3 16 466 495 668
681 682 630 1221 933 1800 1014 130 18 382 18 510 0z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 KiB

+25 -10
View File
@@ -77,6 +77,10 @@ export default {
this.metaInfo = meta
const channelParamObj = configTable.getModeConfig(meta.device.library_name, meta.parameter_set.MODE).channels
const channelArray = this.channel === 'all' ? JSON.parse(this.metaInfo.channels) : Object.keys(channelParamObj).filter(ele => ele !== 'time')
channelArray.filter(el => Object.keys(channelParamObj).includes(el))
if (channelParamObj[channelArray[0]].order) {
channelArray.sort((a, b) => channelParamObj[a].order - channelParamObj[b].order)
}
const channelList = []
// split to different subfile by channel
@@ -87,7 +91,7 @@ export default {
} else {
channelList.push(channelArray)
}
} else if (meta.device.library_name.indexOf('Elite') >= 0) {
} else if (meta.device.library_name.indexOf('Elite') >= 0 || meta.device.library_name.indexOf('PEL') >= 0) {
channelList.push(channelArray)
}
@@ -99,10 +103,12 @@ export default {
// find max raw data need sub file
for (const rawDataIndex of channels) {
const dataLength = meta.raw_data[rawDataIndex].length
if (meta.raw_data[rawDataIndex] !== undefined) {
const dataLength = meta.raw_data[rawDataIndex].length
maxSplitFiles = Math.max(maxSplitFiles, Math.ceil(meta.raw_data[rawDataIndex].length / dataLength))
meta.raw_data[rawDataIndex] = this.chunkArray(meta.raw_data[rawDataIndex], dataLength)
maxSplitFiles = Math.max(maxSplitFiles, Math.ceil(meta.raw_data[rawDataIndex].length / dataLength))
meta.raw_data[rawDataIndex] = this.chunkArray(meta.raw_data[rawDataIndex], dataLength)
}
}
while (fileIndex < maxSplitFiles) {
@@ -129,20 +135,29 @@ export default {
this.downloadInfo.device = [meta.device.library_name.slice(0, 5), meta.device.library_name.slice(5)]
this.downloadInfo.filename = meta.name
this.downloadInfo.size = parseInt(meta.size / (maxSplitFiles))
} else if (meta.device.library_name.indexOf('PEL') >= 0) {
this.downloadInfo.device = ['Elite', 'PEL']
this.downloadInfo.filename = meta.name
this.downloadInfo.size = parseInt(meta.size / (maxSplitFiles))
}
// create new channel info & get sample rate
for (const channel of this.downloadInfo.channel) {
if (this.downloadInfo.channelInfo[channel] === undefined) {
this.downloadInfo.channelInfo[channel] = newChannel()
this.setSampleRateDownload({ channel: channel })
this.downloadInfo.channelInfo[channel] = {
...newChannel(),
...channelParamObj[channel],
}
}
}
// set download ID list
this.clearIDListDownload()
for (const channel of this.downloadInfo.channel) {
this.setIDListDownload({ channel: channel, fileIndex: fileIndex })
if (channelParamObj[channel].type !== 'formula') {
this.setSampleRateDownload({ channel: channel })
this.setIDListDownload({ channel: channel, fileIndex: fileIndex })
}
}
// if create writer
@@ -161,12 +176,12 @@ export default {
const requestArray = []
console.time('download')
// console.log(this.downloadInfo)
console.log(this.downloadInfo)
while (rowIndex - 10 < this.downloadInfo.maxRows) {
// console.log('rowIndex < this.downloadInfo.maxRows', rowIndex, this.downloadInfo.maxRows)
for (const channel of this.downloadInfo.channel) {
columnNum = this.downloadInfo.channelInfo[channel].downloadIDList.length
columnNum = Math.max(this.downloadInfo.channelInfo[channel].downloadIDList.length, columnNum)
for (const idx in this.downloadInfo.channelInfo[channel].downloadIDList) {
const _idx = parseInt(idx)
if (this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] === undefined) {
@@ -195,7 +210,7 @@ export default {
const rawArray = raw.split(' ')
const newArray = rawArray[0] === '' ? [] : rawArray.map((ele, index) => {
// console.log((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale)))
return (index % 2 === 0) ? String((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale))) : channelUnitScale ? String((parseInt(ele) / channelUnitScale).toFixed(Math.log10(channelUnitScale))) : ele
return (index % 2 === 0) ? String((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale))) : channelUnitScale ? String((ele / channelUnitScale)) : ele
})
this.downloadInfo.channelInfo[data.channel].downloadDataBuffer[idx].push(...newArray)
// console.log('rawArray', rawArray)
+31 -14
View File
@@ -80,6 +80,10 @@ export default {
this.metaInfo = meta
const channelParamObj = configTable.getModeConfig(meta.device.library_name, meta.parameter_set.MODE).channels
const channelArray = this.channel === 'all' ? JSON.parse(this.metaInfo.channels) : Object.keys(channelParamObj).filter(ele => ele !== 'time')
channelArray.filter(el => Object.keys(channelParamObj).includes(el))
if (channelParamObj[channelArray[0]].order) {
channelArray.sort((a, b) => channelParamObj[a].order - channelParamObj[b].order)
}
const channelList = []
if (meta.device.library_name.indexOf('Neulive') >= 0) {
@@ -89,9 +93,10 @@ export default {
} else {
channelList.push(channelArray)
}
} else if (meta.device.library_name.indexOf('Elite') >= 0) {
} else if (meta.device.library_name.indexOf('Elite') >= 0 || meta.device.library_name.indexOf('PEL') >= 0) {
channelList.push(channelArray)
}
console.log(channelList)
this.$refs.progressModalRef.show()
@@ -103,15 +108,17 @@ export default {
// find max raw data need sub file
for (const rawDataIndex of Object.keys(meta.raw_data)) {
let dataLength = 0
if (rawDataIndex >= 256) {
dataLength = meta.raw_data[rawDataIndex].length
} else {
dataLength = 10000
}
if (meta.raw_data[rawDataIndex] !== undefined) {
let dataLength = 0
if (rawDataIndex >= 256) {
dataLength = meta.raw_data[rawDataIndex].length
} else {
dataLength = 10000
}
maxSplitFiles = Math.max(maxSplitFiles, Math.ceil(meta.raw_data[rawDataIndex].length / dataLength))
meta.raw_data[rawDataIndex] = this.chunkArray(meta.raw_data[rawDataIndex], dataLength)
maxSplitFiles = Math.max(maxSplitFiles, Math.ceil(meta.raw_data[rawDataIndex].length / dataLength))
meta.raw_data[rawDataIndex] = this.chunkArray(meta.raw_data[rawDataIndex], dataLength)
}
}
while (fileIndex < maxSplitFiles) {
@@ -136,6 +143,10 @@ export default {
this.downloadInfo.device = [meta.device.library_name.slice(0, 5), meta.device.library_name.slice(5)]
this.downloadInfo.filename = meta.name + '-' + (fileIndex + 1).toString()
this.downloadInfo.size = parseInt(meta.size)
} else if (meta.device.library_name.indexOf('PEL') >= 0) {
this.downloadInfo.device = ['Elite', 'PEL']
this.downloadInfo.filename = meta.name
this.downloadInfo.size = parseInt(meta.size / (maxSplitFiles))
}
this.$refs.progressModalRef.setTitle(this.downloadInfo.filename)
@@ -143,15 +154,21 @@ export default {
// get sampleRate && downloadList
for (const channel of this.downloadInfo.channel) {
if (this.downloadInfo.channelInfo[channel] === undefined) {
this.downloadInfo.channelInfo[channel] = newChannel()
this.setSampleRateDownload({ channel: channel })
this.downloadInfo.channelInfo[channel] = {
...newChannel(),
...channelParamObj[channel],
}
}
}
this.clearIDListDownload()
for (const channel of this.downloadInfo.channel) {
this.setIDListDownload({ channel: channel, fileIndex: fileIndex })
if (channelParamObj[channel].type !== 'formula') {
this.setSampleRateDownload({ channel: channel })
this.setIDListDownload({ channel: channel, fileIndex: fileIndex })
}
}
console.log(this.downloadInfo)
// start download data
fileIndex += 1
@@ -165,7 +182,7 @@ export default {
this.$refs.progressModalRef.setValue(parseInt((rowIndex / this.downloadInfo.maxRows) * 100))
// console.log('rowIndex < this.downloadInfo.maxRows', rowIndex, this.downloadInfo.maxRows)
for (const channel of this.downloadInfo.channel) {
columnNum = this.downloadInfo.channelInfo[channel].downloadIDList.length
columnNum = Math.max(this.downloadInfo.channelInfo[channel].downloadIDList.length, columnNum)
for (const idx in this.downloadInfo.channelInfo[channel].downloadIDList) {
const _idx = parseInt(idx)
if (this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] === undefined) {
@@ -194,7 +211,7 @@ export default {
for (const raw of dataArray) {
const rawArray = raw.split(' ')
const newArray = rawArray[0] === '' ? [] : rawArray.map((ele, index) => {
return (index % 2 === 0) ? String((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale))) : channelUnitScale ? String((parseInt(ele) / channelUnitScale).toFixed(Math.log10(channelUnitScale))) : ele
return (index % 2 === 0) ? String((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale))) : channelUnitScale ? String((ele / channelUnitScale)) : ele
})
this.downloadInfo.channelInfo[data.channel].downloadDataBuffer[idx].push(...newArray)
// console.log('rawArray', rawArray)
@@ -223,6 +223,9 @@
<va-popover :message="`Download excel`" placement="top">
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Elite') >= 0" @click.stop="newDownload(props.rowData)"/>
</va-popover>
<va-popover :message="`Download excel`" placement="top">
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('PEL') >= 0" @click.stop="newDownload(props.rowData)"/>
</va-popover>
<va-popover :message="`Download edf`" placement="top">
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Neulive') >= 0" @click.stop="downloadExcel(props.rowData)"/>
</va-popover>
@@ -248,6 +248,11 @@ export default {
let device
// let content
switch (mes[0]) {
case 'device_refresh':
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'get_device_info_all/0',
}))
break
case 'state':
switch (mes[1]) {
case 'device_available':
@@ -22,12 +22,12 @@
<va-item-section class="ml-3" caption>
<!-- <va-button @click="getBattery(device)"> get battery </va-button> -->
<!-- <pre> {{ device.battery }} </pre> -->
<va-item-label v-if="device.library_name.includes('EIS') || device.library_name.includes('TRIG')">
{{ `[${device.memory_board}]` }} {{ device.name }}
<va-item-label v-if="!device.library_name.includes('EDC')">
{{ `[${device.memory_board}]` }} {{ device.name === 'Elite-CPG' ? 'Current Pulse Generator' : device.name }}
</va-item-label>
<va-item-label v-if="device.status !== 0">
<!-- <va-item-label v-if="device.status !== 0">
{{ `[${device.memory_board}]` }} {{ device.name }} <va-icon class="ml-3 fa fa-battery-full" color="rgb(178 180 178)"/>
</va-item-label>
</va-item-label> -->
<va-item-label v-else-if="parseInt((device.battery - 2900) / 10) >= 75">
{{ `[${device.memory_board}]` }} {{ device.name }} <va-icon class="ml-3 fa fa-battery-full" color="#5BC236"/> {{ (parseInt((device.battery - 2900) / 10) > 100 ? 100 : parseInt((device.battery - 2900) / 10)) + '%' }}
</va-item-label>
@@ -55,6 +55,9 @@
<va-item class="pa-0 ma-0 mt-2">
<va-item-section class="ml-3">
<va-item-label>
<va-button @click.stop="quickstart(device)" v-if="device.library_name.includes('PEL') && device.status !== 1" class="px-2 py-0 mr-0" color="success" small>START</va-button>
<va-button @click.stop="quickstop(device)" v-if="device.library_name.includes('PEL') && device.status === 1" class="px-2 py-0 mr-0" color="danger" small>STOP</va-button>
<!-- <va-button @click.stop="quickstart(device)" v-if="device.library_name.includes('CPG')" class="px-2 py-0 mr-0" color="success" small>START</va-button> -->
<va-button @click.stop="start(device)" v-if="device.library_name.includes('Elite') && device.status !== 1" class="px-2 py-0 mr-0" color="success" small>START</va-button>
<va-button @click.stop="stop(device)" v-if="device.library_name.includes('Elite') && device.status === 1" class="px-2 py-0 mr-0" color="danger" small>STOP</va-button>
<va-button id="detectButton" @click.stop="detect(device)" v-if="device.library_name.includes('Elite')" color="primary" class="px-2 py-0 mr-0" small>DETECT</va-button>
@@ -64,8 +67,8 @@
</va-item>
</span>
<div slot="body">
<div class="mt-0 mb-0" style="height: 60vh; overflow-y: scroll; overflow-x: hidden;" :key="'detail' + device.id">
<div>
<div class="mt-0 mb-0" style="height: 60vh; overflow-y: scroll; overflow-x: hidden; scrollbar-width: none;" :key="'detail' + device.id">
<div v-if="device.library_name.includes('Elite') || device.library_name.includes('PEL')">
<file-control-window :ref="`fcwindow_ref_${device.memory_board}`" :device="device" class="pl-0 pr-0" />
</div>
<div>
@@ -155,6 +158,22 @@ export default {
// CanvasChart.methods.resetClicked()
}
},
quickstart: async function (device) {
await this.setArchiveSettings(device.memory_board)
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: device.mac_address,
instruction: 'start',
}))
},
quickstop: function (device) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: device.mac_address,
instruction: 'stop',
}))
},
stop: function (device) {
this.$emit('stop', device)
this.pageToast('The device ' + device.name + ' has been stopped.')
@@ -200,4 +219,9 @@ export default {
filter: brightness(100%);
}
}
.va-collapse__body {
padding-left: 0;
padding-right: 0;
}
</style>
@@ -110,11 +110,64 @@
</va-tree-node>
</va-tree-category>
</div>
<!-- PEL-->
<div v-if="library && library.includes('PEL')">
<div v-if="[0,1].includes(parameter.MODE)">
<PEL :device="device"></PEL>
</div>
<div v-else-if="[3, 4].includes(parameter.MODE)">
<PEL_1 :device="device"></PEL_1>
</div>
<div v-else>
<component
v-for="name in parameterArrayInMode"
:key="name"
:is="parameterTable[name].componentType"
:templateType=1
:withHeader="true"
:parameterName="name"
:inputValue="parameter[name]"
:disable="name === 'CTRL_HIGH_Z_15' && device && device.status === 0"
v-bind="parameterTable[name]"
@parameterChange="parameterChange"
@getParameter="getParameter"
@sendInstruction="sendInstruction"
/>
</div>
</div>
<!-- CPG -->
<div v-if="library && library.includes('CPG')">
<div v-if="parameter.MODE === 0">
<ElectricalStimulation
:parameter="parameter"
:parameterTable="parameterTable"
@parameterChange="parameterChange"
@getParameter="getParameter"
@sendInstruction="sendInstruction"
></ElectricalStimulation>
</div>
<div v-else>
<component
v-for="name in parameterArrayInMode"
:key="name"
:is="parameterTable[name].componentType"
:templateType=1
:withHeader="true"
:parameterName="name"
:inputValue="parameter[name]"
:disable="name === 'CTRL_HIGH_Z_15' && device && device.status === 0"
v-bind="parameterTable[name]"
@parameterChange="parameterChange"
@getParameter="getParameter"
@sendInstruction="sendInstruction"
/>
</div>
</div>
</va-tree-root>
<!-- guide picture button -->
<div>
<vue-final-modal
v-if="library && library.includes('EDC')"
v-if="library"
v-model="showModal"
classes="modal-container"
content-class="modal-content"
@@ -128,7 +181,8 @@
<!-- <va-icon class='fa fa-close modal__close' @click="showModal=false"></va-icon>
<span class="modal__title"></span> -->
<div class="modal__content">
<img :src="require('@/assets/img/elite-wire/' + getImageUrl + '.svg')" class="modal_img" alt="No Pic" draggable="false" >
<img v-if="library.includes('EDC')" :src="require('@/assets/img/elite-wire/' + getImageUrl + '.svg')" class="modal_img" alt="No Pic" draggable="false" >
<img v-if="library.includes('CPG')" :src="require('@/assets/img/elite-wire/CPG_UI_infomation_figure.png')" class="modal_img" alt="No Pic" draggable="false" >
<!-- <img :src="`${pat}`" class="imgaa" alt="No Pic" draggable="false"> -->
</div>
</vue-final-modal>
@@ -150,6 +204,9 @@ import EliteParameterRecordingElitePulseSensing from '../parameter/itemNew/Pulse
import { VueFinalModal } from 'vue-final-modal'
import { mapFields } from 'vuex-map-fields'
import configTable from '@/data/config-table/index'
import ElectricalStimulation from '../parameter/itemNew/ElectricalStimulation/ElectricalStimulation'
import PEL from './itemNew/PEL'
import PEL_1 from './itemNew/PEL_1'
export default {
name: 'EliteParameterRecordingElitezm15',
@@ -165,6 +222,9 @@ export default {
DevMode,
Trigger,
TriggerNew,
ElectricalStimulation,
PEL,
PEL_1,
},
props: {
parameter: {
@@ -14,19 +14,18 @@
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-input
@keyup.enter="instruParameterChange(inputWrite)"
@blur="instruParameterChange(inputWrite)"
class="mb-0"
v-model="inputWrite"
label="Write value (0x3000FF ... )"
style="width: 100px;"
maxlength="34"
/>
<va-button slot="append" class="mr-2 pa-1 shrink" style="width: 2em; height: 2em; border-radius: 50%; font-size: 20px;" small @click="sendInstr('ble_instru_send')">
W
</va-button>
<div>
<h1>
Write
</h1>
</div>
<div class="flex row">
<div>
<textarea class="hexStringArea" v-model="hexInput" @input="formatHexInput" placeholder="Enter hex string..." ref="textarea" maxlength="731"></textarea>
</div>
<div>
<va-icon class="ml-3 fa fa-check-circle custom-icon" size="30px" @click.native="sendInstr('ble_instru_send')"></va-icon>
</div>
</div>
</div>
</div>
@@ -93,6 +92,7 @@ export default {
},
data () {
return {
hexInput: '',
inputWrite: '',
inputNotify: '',
}
@@ -100,6 +100,34 @@ export default {
mqtt: {
},
methods: {
formatHexInput () {
const textarea = this.$refs.textarea
let cursorPosition = textarea.selectionStart
// Remove any non-hex characters (if necessary)
const cleanInput = this.hexInput.replace(/[^A-Fa-f0-9]/g, '')
// Calculate spaces that will be added
const spacesBefore = (this.hexInput.slice(0, cursorPosition).match(/ /g) || []).length
// Add space after every two characters
const formattedInput = cleanInput.match(/.{1,2}/g)?.join(' ') || ''
// Set the formatted input
this.hexInput = formattedInput.toUpperCase()
// Calculate new cursor position
const spacesAfter = (formattedInput.slice(0, cursorPosition).match(/ /g) || []).length
cursorPosition = cursorPosition + (spacesAfter - spacesBefore)
// Set the new cursor position
this.$nextTick(() => {
textarea.setSelectionRange(cursorPosition, cursorPosition)
})
const instructionArray = this.hexInput.split(' ').map(hex => parseInt(hex, 16))
this.$emit('parameterChange', 'BLE_WRITE', instructionArray, true)
},
sendInstr (instr) {
this.$emit('sendInstruction', instr)
},
@@ -112,20 +140,6 @@ export default {
readCisData () {
this.$emit('getParameter', 'ADC_VALUE_I')
},
instruParameterChange (instruction) {
while (instruction.length <= 33) {
instruction += '0'
}
const sendIns = new Array(17).fill(0)
for (let i = 0; i <= 16; i++) {
const startIndex = i * 2
sendIns[i] = instruction.substring(startIndex, startIndex + 2)
sendIns[i] = parseInt(sendIns[i], 16)
}
this.$emit('parameterChange', 'BLE_WRITE', '0:16=' + String(sendIns))
},
},
async mounted () {
},
@@ -136,3 +150,27 @@ export default {
}
</script>
<style>
.hexStringArea {
width: 100%;
height: 100px;
font-size: 14px;
}
.va-tree-category__list-internal-container {
padding-left: 0;
}
.custom-icon {
color: #007bff; /* Default color */
transition: color 0.3s ease;
}
.custom-icon:hover {
color: #0056b3; /* Color when hovering */
}
.custom-icon:active {
color: #003580; /* Color when clicked */
}
</style>
@@ -0,0 +1,201 @@
<template>
<div>
<!-- Main container for the pulse output section -->
<div class="pulse-output" style="width: 95%; justify-content: space-between;">
<!-- PULSE OUTPUT label section -->
<div>
<p style="font-family: 'Inter-Bold';">Pulse Output</p>
</div>
<!-- Timer section, clicking on this triggers setTimer() -->
<div style="display: flex;">
<div class="timer" @click="setTimer" style="cursor: pointer;">
<img src="@/assets/icons/ES_Mode/button-timer.svg">
<p
v-if="parameter.CONTINUE_MODE === 0"
style="font-family: 'Inter'; font-size: 1rem;"
>{{ formattedTime }}</p>
<p v-if="parameter.CONTINUE_MODE === 1"
style="font-family: 'Inter'; font-size: 1.5rem; font-style: normal;"
></p>
</div>
<!-- Buttons for controlling electrode activation -->
<div style="min-width: 80px; text-align: end;">
<!-- Output button visible when electrode is not activated -->
<va-button
:class="isElectrodeActivated ? 'not-visible' : ''"
color="#5cd699"
style="padding: 0.125rem 0.5rem;"
@click="activateElectrode"
small
>output</va-button>
<!-- Stop button visible when electrode is activated -->
<va-button
:class="!isElectrodeActivated ? 'not-visible' : ''"
color="danger"
style="padding: 0.125rem 0.5rem;"
@click="deactiveElectrode"
small
>stop</va-button>
</div>
</div>
</div>
<!-- Test component to handle parameters -->
<PulseOutputSettings
:parameter="parameter"
:parameterTable="parameterTable"
@parameterChange="parameterChange"
@sendInstruction="sendInstruction"
></PulseOutputSettings>
<!-- Timer modal component to handle timer settings -->
<TimerModal :ref="'timer_modal_ref'" :parameter="parameter" :parameterTable="parameterTable" @parameterChange="parameterChange"></TimerModal>
</div>
</template>
<script>
import PulseOutputSettings from './PulseOutputSettings'
import TimerModal from './TimerModal'
export default {
name: 'ElectricalStimulation',
components: {
PulseOutputSettings,
TimerModal,
},
props: {
parameter: {
type: Object,
default: () => {},
},
parameterTable: {
type: Object,
default: () => {},
},
},
computed: {
isElectrodeActivated () {
return this.parameter.ACTIVATE_ELECTRODE === 1
},
formattedTime () {
let totalSeconds = this.parameter.STOP_TIME
const hh = Math.floor(totalSeconds / 3600)
totalSeconds %= 3600
const mm = Math.floor(totalSeconds / 60)
const ss = totalSeconds % 60
// Now conditionally format the output:
let formatted = ''
if (hh > 0) {
formatted += `${hh} h `
}
if (mm > 0) {
formatted += `${mm} m `
}
if (ss > 0 || formatted === '') {
formatted += `${ss} s`
}
return formatted.trim() // Ensure there are no trailing spaces
},
},
created () {
},
data () {
return {
selectedValue: null,
radioItems: [
{ value: 1 },
{ value: 2 },
],
}
},
methods: {
setTimer () {
this.$refs.timer_modal_ref.show()
},
activateElectrode () {
this.parameter.ACTIVATE_ELECTRODE = !this.parameter.ACTIVATE_ELECTRODE
this.parameter.WORKING_ELECTRODE.map((item, index) => {
this.parameter.WORKING_ELECTRODE[index] = 1
})
this.parameterChange('WORKING_ELECTRODE', this.parameter.WORKING_ELECTRODE)
this.parameterChange('ACTIVATE_ELECTRODE', this.parameter.ACTIVATE_ELECTRODE)
this.sendInstruction('output')
},
deactiveElectrode () {
this.parameter.ACTIVATE_ELECTRODE = !this.parameter.ACTIVATE_ELECTRODE
this.parameter.WORKING_ELECTRODE.map((item, index) => {
this.parameter.WORKING_ELECTRODE[index] = 0
})
this.parameterChange('WORKING_ELECTRODE', this.parameter.WORKING_ELECTRODE)
this.parameterChange('ACTIVATE_ELECTRODE', this.parameter.ACTIVATE_ELECTRODE)
this.sendInstruction('deactive_electrode')
},
parameterChange (key, value) {
this.$emit('parameterChange', key, value, false, true)
},
sendInstruction: function (instr) {
this.$emit('sendInstruction', instr)
},
},
}
</script>
<style>
.underline {
width: 100%;
height: 1px;
background-color: #2c3e50;
margin-top: 5px;
}
.pulse-output {
display: flex;
align-items: center;
font-size: 18px;
}
.timer {
display: flex;
align-items: center;
margin-left: 10px;
font-style: italic;
transition: opacity 0.3s ease; /* Smooth transition effect */
}
.timer:hover {
opacity: 0.6;
}
.timer-icon {
font-size: 16px;
margin-right: 5px;
}
.output-button {
background-color: #5cd699;
color: white;
border: none;
padding: 8px 16px;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
}
.output-button:hover {
background-color: #45bf7d;
}
.not-visible {
display: none;
}
</style>
@@ -0,0 +1,423 @@
<template>
<!-- Main container div -->
<div class="container">
<!-- Row for electrode and pulse pattern controls -->
<div class="row flex xl12 lg12 my-3" style="padding: 0 0.25rem;">
<!-- Left side: Electrode section -->
<div class="flex xl6 lg6 py-0 px-0">
<div class="centered-item">
<span>Electrode</span>
<div class="underline"></div>
</div>
<!-- Looping over electrode options to render checkboxes -->
<div class="radio-item" style="padding: 0.25rem; line-height: 30px; justify-content: space-evenly;" v-for="(option, index) in channelOption" :key="'electrode-1-' + option">
<div style="display: flex; align-items: center;">
<!-- Checkbox input for electrode selection -->
<input
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
style="margin-right: 0.25rem; cursor: pointer;"
type="checkbox"
v-model="parameter.ELECTRODE_SELECTOR[index]"
@click="selectedElectrode(index)"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
/>
<span class="number">{{ option }}</span>
</div>
<!-- Play button (active or inactive depending on conditions) -->
<div style="min-width: 30px;">
<div
v-if="parameter.ACTIVATE_ELECTRODE === 1 && parameter.WORKING_ELECTRODE[index] === 1 && parameter.ELECTRODE_SELECTOR[index] === true"
style="display: flex;"
>
<img src="@/assets/icons/ES_Mode/button-play-active.svg">
</div>
<div
v-else
style="display: flex; cursor: pointer;"
@click="startElectrode(index)"
>
<img src="@/assets/icons/ES_Mode/button-play.svg">
</div>
</div>
<!-- Stop button (active or inactive depending on conditions) -->
<div style="min-width: 30px;">
<div
style="display: flex;"
v-if="parameter.ACTIVATE_ELECTRODE === 1 && parameter.WORKING_ELECTRODE[index] === 0 && parameter.ELECTRODE_SELECTOR[index] === true"
>
<img src="@/assets/icons/ES_Mode/button-stop-active.svg">
</div>
<div
v-else
style="display: flex; cursor: pointer;"
@click="stopElectrode(index)"
>
<img src="@/assets/icons/ES_Mode/button-stop.svg">
</div>
</div>
</div>
</div>
<!-- Right side: Pulse Pattern section -->
<div class="flex xl6 lg6 py-0" style="padding-right: 0;">
<div class="centered-item">
<span>Pulse Pattern</span>
<div class="underline"></div>
</div>
<!-- Looping over pulse pattern options to render radio buttons -->
<div class="radio-item" style="padding: 0.25rem; line-height: 30px; justify-content: space-evenly;" v-for="(option, index) in channelOption" :key="'electrode-2-' + option">
<div style="display: flex; align-items: center;">
<!-- Radio button for pattern 1 -->
<input
style="margin-right: 0.25rem; cursor: pointer;"
type="radio"
:name="'pulse-pattern-' + index"
:value="0"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
v-model="parameter.PATTERN_SELECTOR[index]"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@click="bindingPattern(index, 0)"
/>
<span class="number">1</span>
</div>
<div style="display: flex; align-items: center;">
<!-- Radio button for pattern 2 -->
<input
style="margin-right: 0.25rem; cursor: pointer;"
type="radio"
:name="'pulse-pattern-' + index"
:value="1"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
v-model="parameter.PATTERN_SELECTOR[index]"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@click="bindingPattern(index, 1)"
/>
<span class="number">2</span>
</div>
</div>
</div>
</div>
<!-- Section for Pulse Patterns 1 and 2 -->
<div v-for="(value, index) in [1,2]" class="controls" style="width: 100%; margin-bottom: 1rem;" :key="'pattern-' + index">
<p style="font-size: 18px; font-family: 'Inter-Bold';">Pulse Pattern {{ value }}</p>
<div class="row flex xl12 lg12" style="margin-top: 0.5rem; padding: 0 0.25rem; font-family: 'Inter';" >
<!-- Left column: Input fields for Amplitude and Pulse Width -->
<div class="flex xl6 lg6 py-0">
<div>
<p>Amplitude</p>
<!-- Amplitude input field -->
<va-input
v-model="parameter.AMPLITUDE[index]"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@blur="valueChecked('AMPLITUDE', index)"
@keyup.enter="valueChecked('AMPLITUDE', index)"
>
<p slot="append" style="margin-right: 0;" small>
mA
</p>
</va-input>
<p>Pulse Width</p>
<!-- Pulse Width input field -->
<va-input
v-model="parameter.PULSE_WIDTH[index]"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@blur="valueChecked('PULSE_WIDTH', index)"
@keyup.enter="valueChecked('PULSE_WIDTH', index)"
>
<p slot="append" style="margin-right: 0;" small>
µs
</p>
</va-input>
</div>
</div>
<!-- Right column: Radio buttons for Mode selection and Frequency input -->
<div class="flex xl6 lg6 py-0" style="align-content: flex-end;">
<!-- Radio button for Burst Mode -->
<div class="radio-item" style="margin-bottom: 2rem; gap: 8px;">
<input
type="radio"
style="cursor: pointer;"
:value="0"
v-model="parameter.PATTERN_MODE[index]"
:name="'pulse-mode-' + index"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@click="patternModeChange(index, 0)"
/>
<span class="number">Burst Mode</span>
</div>
<!-- Radio button for Frequency Mode -->
<div class="radio-item" style="gap: 8px;">
<input
type="radio"
style="cursor: pointer;"
:value="1"
v-model="parameter.PATTERN_MODE[index]"
:name="'pulse-mode-' + index"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@click="patternModeChange(index, 1)"
/>
<span class="number">Frequency</span>
</div>
<!-- Frequency input field (enabled only in Frequency mode) -->
<div>
<va-input
v-model="parameter.FREQUENCY[index]"
@keyup.enter="valueChecked('FREQUENCY', index)"
@blur="valueChecked('FREQUENCY', index)"
:class="parameter.PATTERN_MODE[index] === 0 || parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.PATTERN_MODE[index] === 0 || parameter.ACTIVATE_ELECTRODE === 1"
>
<p slot="append" style="margin-right: 0;" small>
Hz
</p>
</va-input>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PulseOutputSettings',
// Props passed from the parent component
props: {
parameter: {
type: Object,
default: () => {}, // Default to an empty object if no parameter is provided
},
parameterTable: {
type: Object,
default: () => {}, // Default to an empty object for parameterTable
},
order: Number, // Numerical order for the component (could be used to track different instances)
pulsePattern: Number, // Indicates the pulse pattern selected (1 or 2)
status: String, // Status indicator (could be used for component state, e.g., active/inactive)
},
computed: {
// No computed properties defined in this component
},
// Component's local data
data () {
return {
selectedValue: [], // Stores selected values for the UI components
selectedPattern: null, // Stores the currently selected pattern
channelOption: [1, 2, 3, 4], // Available channel options (4 channels for example)
pulsePatternItems: [ // List of pulse pattern items (1 and 2)
{ value: 1 },
{ value: 2 },
],
}
},
// Methods that define behavior
methods: {
// Toggles the electrode selector for a given index and emits the change
selectedElectrode (index) {
// Toggle the boolean value in ELECTRODE_SELECTOR
this.parameter.ELECTRODE_SELECTOR[index] = !this.parameter.ELECTRODE_SELECTOR[index]
// Emit the change to the parent component
this.parameterChange('ELECTRODE_SELECTOR', this.parameter.ELECTRODE_SELECTOR)
},
// Handles the change of pulse pattern mode (either Frequency or Burst mode)
patternModeChange (index, value) {
// Set the frequency based on the selected mode
if (value === 1) {
this.parameter.FREQUENCY[index] = 1 // Set frequency to 1 for Frequency mode
} else {
this.parameter.FREQUENCY[index] = 0 // Set frequency to 0 for Burst mode
}
// Update PATTERN_MODE and emit the change
this.parameter.PATTERN_MODE[index] = value
this.parameterChange('PATTERN_MODE', this.parameter.PATTERN_MODE)
this.parameterChange('FREQUENCY', this.parameter.FREQUENCY)
},
// Binds the selected pattern to the specified electrode groups
bindingPattern (index, value) {
const temp = value
// Set the pattern for the first two electrodes if index is 0 or 1
if (index === 0 || index === 1) {
this.parameter.PATTERN_SELECTOR[0] = temp
this.parameter.PATTERN_SELECTOR[1] = temp
// Set the pattern for the second group of electrodes if index is 2 or 3
} else if (index === 2 || index === 3) {
this.parameter.PATTERN_SELECTOR[2] = temp
this.parameter.PATTERN_SELECTOR[3] = temp
}
// Emit the updated PATTERN_SELECTOR
this.parameterChange('PATTERN_SELECTOR', this.parameter.PATTERN_SELECTOR)
},
// Starts the electrode for the specified index
startElectrode (index) {
// Check if the electrode can be activated
if (this.parameter.ACTIVATE_ELECTRODE === 0 || this.parameter.ELECTRODE_SELECTOR[index] === false) {
return // Do nothing if the electrode is not selected or activation is off
}
// Toggle the WORKING_ELECTRODE state and emit the change
this.parameter.WORKING_ELECTRODE[index] = !this.parameter.WORKING_ELECTRODE[index]
this.parameterChange('WORKING_ELECTRODE', this.parameter.WORKING_ELECTRODE)
// Send an instruction to start the electrode (external function call)
this.sendInstruction('resume_electrode_' + index)
},
// Stops the electrode for the specified index
stopElectrode (index) {
// Check if the electrode can be deactivated
if (this.parameter.ACTIVATE_ELECTRODE === 0 || this.parameter.ELECTRODE_SELECTOR[index] === false) {
return // Do nothing if the electrode is not selected or activation is off
}
// Toggle the WORKING_ELECTRODE state and emit the change
this.parameter.WORKING_ELECTRODE[index] = !this.parameter.WORKING_ELECTRODE[index]
this.parameterChange('WORKING_ELECTRODE', this.parameter.WORKING_ELECTRODE)
// Send an instruction to stop the electrode (external function call)
this.sendInstruction('suspend_electrode_' + index)
},
// Ensures the value is within the acceptable range, rounded to the grid
valueChecked (parameterName, index) {
// Get the grid, minimum, and maximum values from the parameter table
const grid = this.parameterTable[parameterName].grid
const min = this.parameterTable[parameterName].range[0]
const max = this.parameterTable[parameterName].range[1]
// Round the value to the nearest grid and ensure it is within bounds
let value = Number(this.parameter[parameterName][index])
value = Math.round(value / grid) * grid
if (value < min) {
value = min // Set to min if it's too small
} else if (value > max) {
value = max // Set to max if it's too large
}
// Update the parameter and emit the change
this.parameter[parameterName][index] = value
this.parameterChange(parameterName, this.parameter[parameterName])
},
// Emits the parameter change event to the parent component
parameterChange (parameterName, value) {
this.$emit('parameterChange', parameterName, value)
},
// Sends instructions (e.g., start/stop electrode) to the parent component or external system
sendInstruction: function (instr) {
this.$emit('sendInstruction', instr)
},
},
}
</script>
<style scoped>
.centered-container {
display: flex;
justify-content: space-around;
align-items: center;
width: 100%;
}
.centered-item {
text-align: center;
}
.centered-item span {
display: block;
font-family: 'Inter';
font-size: 16px;
font-weight: 500;
color: #2c3e50;
}
.container {
align-items: center;
gap: 20px;
width: 95%;
}
.radio-group {
display: flex;
align-items: center;
flex-direction: column;
gap: 20px;
}
.radio-item {
display: flex;
align-items: center;
}
.disable-input {
opacity: 0.5;
}
input[type="radio"] {
/* remove standard background appearance */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/* create custom radiobutton appearance */
display: inline-block;
width: 21px;
height: 21px;
padding: 2px;
/* background-color only for content */
background-clip: content-box;
border: 2px solid #bbbbbb;
background-color: #ffffff;
border-radius: 50%;
}
/* appearance for checked radiobutton */
input[type="radio"]:checked {
background-color: #858dd5;
}
input[type="checkbox"] {
/* remove standard background appearance */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/* create custom radiobutton appearance */
display: inline-block;
width: 21px;
height: 21px;
padding: 2px;
/* background-color only for content */
background-clip: content-box;
border: 2px solid #bbbbbb;
background-color: #ffffff;
border-radius: 50%;
}
/* appearance for checked radiobutton */
input[type="checkbox"]:checked {
background-color: #858dd5;
}
</style>
@@ -0,0 +1,238 @@
<template>
<div>
<va-modal
v-model="showModal"
hideDefaultActions
noOutsideDismiss
>
<div class="timer-container">
<h2 style="font-size: 20px;">Timer</h2>
<div class="timer-inputs">
<div>
<input
type="number"
v-model="hours"
min="0"
class="time-input"
@click="mode = null"
/><span style="padding-left: 10px;">h</span>
</div>
<div>
<input
type="number"
v-model="minutes"
min="0"
class="time-input"
@click="mode = null"
/><span style="padding-left: 10px;">m</span>
</div>
<div>
<input
type="number"
v-model="seconds"
min="0"
class="time-input"
@click="mode = null"
/><span style="padding-left: 10px;">s</span>
</div>
</div>
<div class="mode-selection">
<input
type="radio"
id="continueMode"
:value="'infinity'"
:checked="mode === 'infinity'"
@click="toggleMode"
/>
<label
for="continueMode"
class="radio-text"
>continuous mode, </label>
</div>
<div style="display: flex; flex-direction: row; align-items: center; justify-content: flex-end;">
<p class="time-text">{{ formattedTime }}</p>
<va-button @click="setTimer" small>SET</va-button>
</div>
</div>
</va-modal>
</div>
</template>
<script>
export default {
name: 'TimerModal',
props: {
parameter: {
type: Object,
default: () => {},
},
},
computed: {
formattedTime () {
let totalSeconds = 0
totalSeconds += (parseInt(this.seconds) || 0)
totalSeconds += (parseInt(this.minutes) || 0) * 60
totalSeconds += (parseInt(this.hours) || 0) * 3600
const hh = Math.floor(totalSeconds / 3600)
totalSeconds %= 3600
const mm = Math.floor(totalSeconds / 60)
const ss = totalSeconds % 60
// Now conditionally format the output:
let formatted = ''
if (hh > 0) {
formatted += `${hh} h `
}
if (mm > 0) {
formatted += `${mm} m `
}
if (ss > 0) {
formatted += `${ss} s`
}
return formatted.trim() // Ensure there are no trailing spaces
},
},
data () {
return {
hours: '',
minutes: '',
seconds: '',
mode: null,
showModal: false,
}
},
methods: {
toggleMode () {
// If the mode is already selected, uncheck it (set it to null)
if (this.mode === 'infinity') {
this.mode = null
} else {
this.mode = 'infinity' // Otherwise, select the 'infinity' mode
this.hours = ' '
this.minutes = ' '
this.seconds = ' '
}
},
setTimer () {
// Your logic to handle timer setting, like validation or starting the timer
console.log('Timer set with', this.hours, this.minutes, this.seconds, this.mode)
let totalSeconds = 0
if (this.seconds > 0) {
totalSeconds += parseInt(this.seconds)
}
if (this.minutes > 0) {
totalSeconds += parseInt(this.minutes) * 60
}
if (this.hours > 0) {
totalSeconds += parseInt(this.hours) * 3600
}
this.$emit('parameterChange', 'STOP_TIME', totalSeconds)
this.$emit('parameterChange', 'CONTINUE_MODE', this.mode === 'infinity' ? 1 : 0)
this.hide()
},
initParameter () {
this.mode = this.parameter.CONTINUE_MODE === 1 ? 'infinity' : null
if (this.parameter.CONTINUE_MODE === 1) return
let totalSeconds = this.parameter.STOP_TIME
const hh = Math.floor(totalSeconds / 3600)
totalSeconds %= 3600
const mm = Math.floor(totalSeconds / 60)
const ss = totalSeconds % 60
this.hours = hh > 0 ? hh : ''
this.minutes = mm > 0 ? mm : ''
this.seconds = ss > 0 ? ss : ''
},
show () {
this.initParameter()
this.showModal = true
},
hide () {
this.showModal = false
},
},
}
</script>
<style scoped>
.timer-container {
display: flex;
flex-direction: column;
/* align-items: center; */
gap: 15px;
}
.timer-inputs {
display: flex;
gap: 10px;
}
.time-input {
width: 80px;
height: 40px;
text-align: right;
font-size: 1.2em;
border: 1px solid #cccccc;
border-radius: 10px;
padding: 5px;
}
.mode-selection {
display: flex;
align-items: center;
gap: 10px;
}
input[type="radio"] {
/* remove standard background appearance */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/* create custom radiobutton appearance */
display: inline-block;
width: 21px;
height: 21px;
padding: 2px;
/* background-color only for content */
background-clip: content-box;
border: 2px solid #bbbbbb;
background-color: #ffffff;
border-radius: 50%;
}
/* appearance for checked radiobutton */
input[type="radio"]:checked {
background-color: #858dd5;
}
.radio-text {
font-family: Inter;
font-size: 16px;
font-weight: 500;
text-align: left;
color: #2c3e50;
}
.time-text {
font-family: Inter;
font-size: 14px;
font-weight: 500;
line-height: 19.36px;
text-align: left;
}
.disable-infinite-input {
color: #bdbdbd;
}
</style>
@@ -0,0 +1,154 @@
<template>
<div>
<div style="height: 60vh; overflow-y: scroll; overflow-x: hidden; scrollbar-width: none;">
<va-toggle v-model="switchInput" @click.native="setSwitch" flat small></va-toggle>
<div class="px-2">
<div v-if="switchInput === true">
<div>
<h1 style="font-size: 20px;">Manual</h1>
</div>
<div style="display: flex; margin-top: 0.5rem; margin-bottom: 1rem; width: 90%; justify-content: flex-start;">
<input type="text" class="flex-item" v-model="input1" @blur="setPulse">
<input type="text" class="flex-item" v-model="input2" @blur="setPulse">
<input type="text" class="flex-item" v-model="input3" @blur="setPulse">
<va-button class="pa-0 ma-0 mt-1 circle-button" @click="tag" small color="dark">S
</va-button>
</div>
</div>
<div v-if="switchInput === false">
<div>
<h1 style="font-size: 20px;">Pattern</h1>
</div>
<div style="display: flex; margin-top: 0.5rem; margin-bottom: 1rem; width: 90%; justify-content: flex-start;">
<input type="text" class="flex-item" v-model.lazy="input5" @blur="setPattern">
<va-button id="" class="pa-0 ma-0 mt-1 circle-button" @click="tag" small color="dark">S
</va-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
import { mapFields } from 'vuex-map-fields'
export default {
name: 'PEL',
components: {
},
props: {
device: {
type: Object,
required: true,
},
},
data () {
return {
input1: '0',
input2: '0',
input3: '0',
input4: '0',
input5: '0',
switchInput: false,
clickEvent: null,
}
},
computed: {
...mapFields('', [
'developerMode',
]),
},
methods: {
setPulse: function () {
this.setParameter('PULSE', [this.hexToInt(this.input1), this.hexToInt(this.input2), this.hexToInt(this.input3)])
},
setPulseWithSendInstruction: function (e) {
const activeElement = document.activeElement
if (activeElement && activeElement.tagName === 'INPUT') {
activeElement.blur()
}
this.setParameter('PULSE', [this.hexToInt(this.input1), this.hexToInt(this.input2), this.hexToInt(this.input3)])
this.tag()
},
setPattern: function () {
this.setParameter('PATTERN', this.input5)
},
setPatternWithSendInstruction: function (e) {
const activeElement = document.activeElement
if (activeElement && activeElement.tagName === 'INPUT') {
activeElement.blur()
}
this.setParameter('PATTERN', this.input5)
this.tag()
},
setSwitch: function () {
this.setParameter('PATTERN_SWITCH', this.switchInput)
},
intToHex: function (int) {
return int.toString(2).padStart(4, '0')
},
hexToInt (hex) {
return parseInt(hex, 2)
},
mqttPublish: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
setParameter: function (parameterName, parameterValue) {
this.mqttPublish(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: this.device.mac_address,
parameter: parameterName,
content: parameterValue,
}))
},
tag: function () {
this.mqttPublish(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: this.device.mac_address,
instruction: 'get_data',
}))
},
},
mounted () {
this.input1 = this.intToHex(this.device.configuration.PULSE[0])
this.input2 = this.intToHex(this.device.configuration.PULSE[1])
this.input3 = this.intToHex(this.device.configuration.PULSE[2])
this.input5 = this.device.configuration.PATTERN
this.switchInput = Boolean(this.device.configuration.PATTERN_SWITCH)
// add event listener for enter key
this.clickEvent = (e) => {
if (e.key === 'Enter') {
if ([0, 1].includes(this.device.configuration.MODE)) {
if (this.device.status === 1) {
if (this.switchInput) {
this.setPulseWithSendInstruction()
} else {
this.setPatternWithSendInstruction()
}
}
}
}
}
document.addEventListener('keydown', this.clickEvent)
},
destroyed () {
document.removeEventListener('keydown', this.clickEvent)
},
}
</script>
<style lang="scss">
.no-dark-style-va-button {
&:focus {
filter: brightness(100%);
}
}
.flex-item {
width: 55px; /* Max width of 75px */
padding: 5px;
margin-right: 1rem;
}
</style>
@@ -0,0 +1,113 @@
<template>
<div>
<div style="height: 60vh; overflow-y: scroll; overflow-x: hidden; scrollbar-width: none;">
<div>
<h1 style="font-size: 20px;">Pattern Set</h1>
</div>
<div style="display: flex; margin-top: 0.5rem; margin-bottom: 1rem; width: 90%; justify-content: flex-start; align-items: center;">
<span>From</span> <input type="text" class="flex-item mx-2" v-model="inputMin" @blur="setPatternMin">
<span>To</span> <input type="text" class="flex-item mx-2" v-model="inputMax" @blur="setPatternMax">
</div>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
import { mapFields } from 'vuex-map-fields'
export default {
name: 'PEL_1',
components: {
},
props: {
device: {
type: Object,
required: true,
},
},
data () {
return {
input1: '0',
input2: '0',
input3: '0',
input4: '0',
input5: '0',
inputMax: '0',
inputMin: '0',
switchInput: false,
}
},
computed: {
...mapFields('', [
'developerMode',
]),
},
methods: {
setPulse: function () {
this.setParameter('PULSE', [this.hexToInt(this.input1), this.hexToInt(this.input2), this.hexToInt(this.input3)])
},
setPattern: function () {
this.setParameter('PATTERN', this.input5)
},
setPatternMax: function () {
if (this.inputMax < this.inputMin) {
this.inputMax = this.inputMin + 1
} else if (this.inputMax > 100) {
this.inputMax = 100
}
this.setParameter('PATTERN_MAX', this.inputMax)
},
setPatternMin: function () {
if (this.inputMax < this.inputMin) {
this.inputMin = this.inputMax - 1
} else if (this.inputMax < 1) {
this.inputMin = 1
}
this.setParameter('PATTERN_MIN', this.inputMin)
},
setSwitch: function () {
this.setParameter('PATTERN_SWITCH', this.switchInput)
},
intToHex: function (int) {
return int.toString(2).padStart(4, '0')
},
hexToInt (hex) {
return parseInt(hex, 2)
},
mqttPublish: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
setParameter: function (parameterName, parameterValue) {
this.mqttPublish(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: this.device.mac_address,
parameter: parameterName,
content: parameterValue,
}))
},
},
mounted () {
this.inputMax = this.device.configuration.PATTERN_MAX
this.inputMin = this.device.configuration.PATTERN_MIN
},
destroyed () {
},
}
</script>
<style lang="scss">
.no-dark-style-va-button {
&:focus {
filter: brightness(100%);
}
}
.flex-item {
width: 55px; /* Max width of 75px */
padding: 5px;
margin-right: 1rem;
}
</style>
+98
View File
@@ -0,0 +1,98 @@
export default {
name: 'Dev Mode',
parameter: ['ADC_VALUE_I'],
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'auto',
},
0: {
name: '0',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
1: {
name: '1',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
2: {
name: '2',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
3: {
name: '3',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
},
charts: {
default: [
{
name: 'Dev Mode',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'dev',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,14 @@
export default {
name: 'Electrial Stimulation',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
},
charts: {
default: [
],
},
}
+98
View File
@@ -0,0 +1,98 @@
import EletricalStimulation from './EletricalStimulation'
import DevMode from './DevMode'
/**
* Number-type-parameter
* PARAMETER_TITLE :{
* @param type value-type
* @param showName name
* @param componentType component-type
* @param range component-range
* @param defaultValue default-value
* @param defaultUnit default-unit
* @param downloadUnit download-unit
* @param unit unit-table
* @param outputRawData function return raw data
* @param outputReadabilityData function return user data
* }
*/
/**
* Array-type-parameter
* PARAMETER_TITLE :{
* @param type value-type
* @param showName name
* @param componentType component-type
* @param options select-options
* @param range select-range
* @param defaultValue default-value
* @param outputRawData function return raw data
* @param outputReadabilityData function return user data
* }
*/
const CPG = {
ADC_VALUE_I: {
type: 'none',
showName: 'Instruction',
componentType: 'dev-mode',
},
PULSE_WIDTH: {
type: 'number',
showName: 'Pulse Width',
componentType: 'input',
range: [1, 10000],
grid: 1,
defaultValue: 0,
defaultUnit: 'us',
downloadUnit: 'us',
},
AMPLITUDE: {
type: 'number',
showName: 'Amplititude',
componentType: 'input',
range: [0.5, 50],
grid: 0.5,
defaultValue: 0,
defaultUnit: 'mA',
downloadUnit: 'mA',
},
FREQUENCY: {
type: 'number',
showName: 'Frequency',
componentType: 'input',
range: [1, 10000],
grid: 1,
defaultValue: 1,
defaultUnit: 'Hz',
downloadUnit: 'Hz',
},
BurstMode: {
type: 'bool',
showName: 'Burst Mode',
},
MODE_OPTIONS: [
{
id: 0,
description: 'Eletrical Stimulation',
img_src: 'CPG_UI_infomation_figure',
highz: 1,
},
{
id: 1,
description: 'Dev Mode',
img_src: 'DevM-Wire',
},
],
MODE: {
0: EletricalStimulation,
1: DevMode,
},
}
export default CPG
+98
View File
@@ -0,0 +1,98 @@
export default {
name: 'Dev Mode',
parameter: ['ADC_VALUE_I'],
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'auto',
},
0: {
name: '0',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
1: {
name: '1',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
2: {
name: '2',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
3: {
name: '3',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
},
charts: {
default: [
{
name: 'Dev Mode',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'dev',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
+176
View File
@@ -0,0 +1,176 @@
export default {
name: 'IOPH',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
// 0: {
// order: 0,
// name: 'R1',
// physicalQuantity: 'mV',
// unit: {
// mv: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
// 1: {
// order: 1,
// name: 'R2',
// physicalQuantity: 'mV',
// unit: {
// mV: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
2: {
order: 2,
name: 'output_vo',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
3: {
order: 3,
name: 'output_vc',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
4: {
order: 4,
name: 'output_ve',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
// 5: {
// order: 5,
// name: 'R1 Float',
// physicalQuantity: 'mV',
// unit: {
// mv: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
6: {
order: 6,
name: 'G',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
7: {
order: 7,
name: 'VO Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
8: {
order: 8,
name: 'VCC Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
9: {
order: 9,
name: 'VEE Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
10: {
order: 5,
name: 'Pattern',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
// 11: {
// order: 11,
// name: 'Pattern Manual',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
12: {
order: 12,
name: 'VO-VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
13: {
order: 13,
name: 'current (VxG) ',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
14: {
order: 14,
name: 'VO-VCC',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
},
charts: {
default: [
],
},
}
+176
View File
@@ -0,0 +1,176 @@
export default {
name: 'IOPL',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
// 0: {
// order: 0,
// name: 'R1',
// physicalQuantity: 'mV',
// unit: {
// mv: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
// 1: {
// order: 1,
// name: 'R2',
// physicalQuantity: 'mV',
// unit: {
// mV: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
2: {
order: 2,
name: 'output_vo',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
3: {
order: 3,
name: 'output_vc',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
4: {
order: 4,
name: 'output_ve',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
// 5: {
// order: 5,
// name: 'R1 Float',
// physicalQuantity: 'mV',
// unit: {
// mv: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
6: {
order: 6,
name: 'G',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
7: {
order: 7,
name: 'VO Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
8: {
order: 8,
name: 'VCC Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
9: {
order: 9,
name: 'VEE Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
10: {
order: 5,
name: 'Pattern',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
// 11: {
// order: 11,
// name: 'Pattern Manual',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
12: {
order: 12,
name: 'VCC-VO',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
13: {
order: 13,
name: 'current (VxG) ',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
14: {
order: 14,
name: 'VO-VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
},
charts: {
default: [
],
},
}
+176
View File
@@ -0,0 +1,176 @@
export default {
name: 'R-external calibration',
parameter: [],
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
// 0: {
// order: 0,
// name: 'R1',
// physicalQuantity: 'mV',
// unit: {
// mv: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
// 1: {
// order: 1,
// name: 'R2',
// physicalQuantity: 'mV',
// unit: {
// mV: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
2: {
order: 2,
name: 'output_vo',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
3: {
order: 3,
name: 'output_vc',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
4: {
order: 4,
name: 'output_ve',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
// 5: {
// order: 5,
// name: 'R1 Float',
// physicalQuantity: 'mV',
// unit: {
// mv: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
6: {
order: 6,
name: 'G',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
7: {
order: 7,
name: 'VO Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
8: {
order: 8,
name: 'VCC Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
9: {
order: 9,
name: 'VEE Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
// 10: {
// order: 5,
// name: 'Pattern',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
11: {
order: 5,
name: 'Pattern Manual',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
12: {
order: 12,
name: 'VO-VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
13: {
order: 13,
name: 'current (VxG) ',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
14: {
order: 14,
name: 'VO-VCC',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
},
charts: {
default: [
],
},
}
@@ -0,0 +1,174 @@
export default {
name: 'Electrial Stimulation',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
10: {
order: 10,
name: 'Pattern',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
11: {
order: 11,
name: 'Pattern Manual',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
0: {
order: 0,
name: 'R1',
physicalQuantity: 'mV',
unit: {
mv: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
1: {
order: 1,
name: 'R2',
physicalQuantity: 'mV',
unit: {
mV: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
order: 2,
name: 'VO',
physicalQuantity: 'mV',
unit: {
mV: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
3: {
order: 3,
name: 'VCC',
physicalQuantity: 'mV',
unit: {
mV: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
4: {
order: 4,
name: 'VEE',
physicalQuantity: 'mV',
unit: {
mV: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
5: {
order: 5,
name: 'R1 Float',
physicalQuantity: 'mV',
unit: {
mv: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
6: {
order: 6,
name: 'R2 Float',
physicalQuantity: 'mV',
unit: {
mv: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
7: {
order: 7,
name: 'VO Float',
physicalQuantity: 'mV',
unit: {
mv: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
8: {
order: 8,
name: 'VCC Float',
physicalQuantity: 'mV',
unit: {
mv: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
9: {
order: 9,
name: 'VEE Float',
physicalQuantity: 'mV',
unit: {
mv: 1,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
12: {
order: 12,
type: 'formula',
name: '∆VO',
physicalQuantity: 'mV',
unit: {
mV: 1,
},
formulaTarget: [2, 4],
formula: (data1, data2) => {
return data1 - data2
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
// 13: {
// type: 'formula',
// name: 'Current [A]',
// physicalQuantity: 'A',
// unit: {
// A: 1,
// },
// formula: (data) => {
// return (data[2] - data[4])
// },
// defaultUnit: 'A',
// downloadUnit: 'A',
// },
},
charts: {
default: [
],
},
}
@@ -0,0 +1,146 @@
export default {
name: 'Electrial Stimulation',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
// 0: {
// order: 0,
// name: 'mem_board_id',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 1: {
// order: 1,
// name: 'packet_seq',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 2: {
// order: 2,
// name: 'notify_time',
// physicalQuantity: 'ms',
// unit: {
// ms: 1,
// },
// defaultUnit: 'ms',
// downloadUnit: 'ms',
// },
3: {
order: 4,
name: 'ACS37030_VREF',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
4: {
order: 5,
name: 'ACS37030_OUT',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
5: {
order: 6,
name: 'OUT (VO)',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
6: {
order: 7,
name: 'VCC',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
7: {
order: 8,
name: 'VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
8: {
order: 9,
name: 'ACS37030_current',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
9: {
order: 2,
name: 'Pattern id',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
// 10: {
// order: 10,
// name: 'Pattern mask',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
11: {
order: 3,
name: 'G',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
},
charts: {
default: [
],
},
}
+81
View File
@@ -0,0 +1,81 @@
import SelectResistor from './SelectResistor'
import SelectResistorFull from './SelectResistorFull'
import DevMode from './DevMode'
import IOPH from './IOPH'
import IOPL from './IOPL'
import RC from './RC'
/**
* Number-type-parameter
* PARAMETER_TITLE :{
* @param type value-type
* @param showName name
* @param componentType component-type
* @param range component-range
* @param defaultValue default-value
* @param defaultUnit default-unit
* @param downloadUnit download-unit
* @param unit unit-table
* @param outputRawData function return raw data
* @param outputReadabilityData function return user data
* }
*/
/**
* Array-type-parameter
* PARAMETER_TITLE :{
* @param type value-type
* @param showName name
* @param componentType component-type
* @param options select-options
* @param range select-range
* @param defaultValue default-value
* @param outputRawData function return raw data
* @param outputReadabilityData function return user data
* }
*/
const PEL20 = {
ADC_VALUE_I: {
type: 'none',
showName: 'Instruction',
componentType: 'dev-mode',
},
MODE_OPTIONS: [
{
id: 0,
description: 'SELECT RESISTOR',
},
{
id: 1,
description: 'SELECT RESISTOR FULL DATA',
},
{
id: 3,
description: 'IOPH',
},
{
id: 4,
description: 'IOPL',
},
{
id: 2,
description: 'Dev Mode',
},
{
id: 5,
description: 'R-external calibration',
},
],
MODE: {
0: SelectResistor,
1: SelectResistorFull,
2: DevMode,
3: IOPH,
4: IOPL,
5: RC,
},
}
export default PEL20
+98
View File
@@ -0,0 +1,98 @@
export default {
name: 'Dev Mode',
parameter: ['ADC_VALUE_I'],
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'auto',
},
0: {
name: '0',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
1: {
name: '1',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
2: {
name: '2',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
3: {
name: '3',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
},
charts: {
default: [
{
name: 'Dev Mode',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'dev',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
+176
View File
@@ -0,0 +1,176 @@
export default {
name: 'IOPH',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
// 0: {
// order: 0,
// name: 'mem_board_id',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 1: {
// order: 1,
// name: 'packet_seq',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 2: {
// order: 2,
// name: 'notify_time',
// physicalQuantity: 'ms',
// unit: {
// ms: 1,
// },
// defaultUnit: 'ms',
// downloadUnit: 'ms',
// },
3: {
order: 4,
name: 'ACS37030_VREF',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
4: {
order: 5,
name: 'ACS37030_OUT',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
5: {
order: 6,
name: 'OUT (VO)',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
6: {
order: 7,
name: 'VCC',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
7: {
order: 8,
name: 'VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
8: {
order: 9,
name: 'ACS37030_current',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
9: {
order: 2,
name: 'Pattern id',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
// 10: {
// order: 10,
// name: 'Pattern mask',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
11: {
order: 3,
name: 'G',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
12: {
order: 10,
name: 'VO-VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
13: {
order: 11,
name: 'current (VxG) ',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
14: {
order: 12,
name: 'VO-VCC',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
},
charts: {
default: [
],
},
}
+176
View File
@@ -0,0 +1,176 @@
export default {
name: 'IOPL',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
// 0: {
// order: 0,
// name: 'mem_board_id',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 1: {
// order: 1,
// name: 'packet_seq',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 2: {
// order: 2,
// name: 'notify_time',
// physicalQuantity: 'ms',
// unit: {
// ms: 1,
// },
// defaultUnit: 'ms',
// downloadUnit: 'ms',
// },
3: {
order: 4,
name: 'ACS37030_VREF',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
4: {
order: 5,
name: 'ACS37030_OUT',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
5: {
order: 6,
name: 'OUT (VO)',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
6: {
order: 7,
name: 'VCC',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
7: {
order: 8,
name: 'VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
8: {
order: 9,
name: 'ACS37030_current',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
9: {
order: 2,
name: 'Pattern id',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
// 10: {
// order: 10,
// name: 'Pattern mask',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
11: {
order: 3,
name: 'G',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
12: {
order: 10,
name: 'VCC-VO',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
13: {
order: 11,
name: 'current (VxG) ',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
14: {
order: 12,
name: 'VO-VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
},
charts: {
default: [
],
},
}
+176
View File
@@ -0,0 +1,176 @@
export default {
name: 'R-external calibration',
parameter: [],
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
// 0: {
// order: 0,
// name: 'R1',
// physicalQuantity: 'mV',
// unit: {
// mv: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
// 1: {
// order: 1,
// name: 'R2',
// physicalQuantity: 'mV',
// unit: {
// mV: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
2: {
order: 2,
name: 'output_vo',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
3: {
order: 3,
name: 'output_vc',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
4: {
order: 4,
name: 'output_ve',
physicalQuantity: 'raw',
unit: {
raw: 1,
},
defaultUnit: 'raw',
downloadUnit: 'raw',
},
// 5: {
// order: 5,
// name: 'R1 Float',
// physicalQuantity: 'mV',
// unit: {
// mv: 1,
// },
// defaultUnit: 'mV',
// downloadUnit: 'mV',
// },
6: {
order: 6,
name: 'G',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
7: {
order: 7,
name: 'VO Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
8: {
order: 8,
name: 'VCC Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
9: {
order: 9,
name: 'VEE Float',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
// 10: {
// order: 5,
// name: 'Pattern',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
11: {
order: 5,
name: 'Pattern Manual',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
12: {
order: 12,
name: 'VO-VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
13: {
order: 13,
name: 'current (VxG) ',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
14: {
order: 14,
name: 'VO-VCC',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
},
charts: {
default: [
],
},
}
@@ -0,0 +1,146 @@
export default {
name: 'Electrial Stimulation',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
// 0: {
// order: 0,
// name: 'mem_board_id',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 1: {
// order: 1,
// name: 'packet_seq',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 2: {
// order: 2,
// name: 'notify_time',
// physicalQuantity: 'ms',
// unit: {
// ms: 1,
// },
// defaultUnit: 'ms',
// downloadUnit: 'ms',
// },
3: {
order: 4,
name: 'ACS37030_VREF',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
4: {
order: 5,
name: 'ACS37030_OUT',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
5: {
order: 6,
name: 'OUT (VO)',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
6: {
order: 7,
name: 'VCC',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
7: {
order: 8,
name: 'VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
8: {
order: 9,
name: 'ACS37030_current',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
9: {
order: 2,
name: 'Pattern id',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
// 10: {
// order: 10,
// name: 'Pattern mask',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
11: {
order: 3,
name: 'G',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
},
charts: {
default: [
],
},
}
@@ -0,0 +1,146 @@
export default {
name: 'Electrial Stimulation',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
time: {
name: 'Time',
physicalQuantity: 'ms',
unit: {
ms: 1,
s: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
// 0: {
// order: 0,
// name: 'mem_board_id',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 1: {
// order: 1,
// name: 'packet_seq',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
// 2: {
// order: 2,
// name: 'notify_time',
// physicalQuantity: 'ms',
// unit: {
// ms: 1,
// },
// defaultUnit: 'ms',
// downloadUnit: 'ms',
// },
3: {
order: 4,
name: 'ACS37030_VREF',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
4: {
order: 5,
name: 'ACS37030_OUT',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
5: {
order: 6,
name: 'OUT (VO)',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
6: {
order: 7,
name: 'VCC',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
7: {
order: 8,
name: 'VEE',
physicalQuantity: 'V',
unit: {
V: 1,
},
defaultUnit: 'V',
downloadUnit: 'V',
},
8: {
order: 9,
name: 'ACS37030_current',
physicalQuantity: 'A',
unit: {
A: 1,
},
defaultUnit: 'A',
downloadUnit: 'A',
},
9: {
order: 2,
name: 'Pattern id',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
// 10: {
// order: 10,
// name: 'Pattern mask',
// physicalQuantity: '',
// unit: {
// '': 1,
// },
// defaultUnit: '',
// downloadUnit: '',
// },
11: {
order: 3,
name: 'G',
physicalQuantity: '',
unit: {
'': 1,
},
defaultUnit: '',
downloadUnit: '',
},
},
charts: {
default: [
],
},
}
+81
View File
@@ -0,0 +1,81 @@
import SelectResistor from './SelectResistor'
import SelectResistorFull from './SelectResistorFull'
import DevMode from './DevMode'
import IOPH from './IOPH'
import IOPL from './IOPL'
import RC from './RC'
/**
* Number-type-parameter
* PARAMETER_TITLE :{
* @param type value-type
* @param showName name
* @param componentType component-type
* @param range component-range
* @param defaultValue default-value
* @param defaultUnit default-unit
* @param downloadUnit download-unit
* @param unit unit-table
* @param outputRawData function return raw data
* @param outputReadabilityData function return user data
* }
*/
/**
* Array-type-parameter
* PARAMETER_TITLE :{
* @param type value-type
* @param showName name
* @param componentType component-type
* @param options select-options
* @param range select-range
* @param defaultValue default-value
* @param outputRawData function return raw data
* @param outputReadabilityData function return user data
* }
*/
const PEL30 = {
ADC_VALUE_I: {
type: 'none',
showName: 'Instruction',
componentType: 'dev-mode',
},
MODE_OPTIONS: [
{
id: 0,
description: 'SELECT RESISTOR',
},
{
id: 1,
description: 'SELECT RESISTOR FULL DATA',
},
{
id: 3,
description: 'IOPH',
},
{
id: 4,
description: 'IOPL',
},
{
id: 2,
description: 'Dev Mode',
},
{
id: 5,
description: 'R-external calibration',
},
],
MODE: {
0: SelectResistor,
1: SelectResistorFull,
2: DevMode,
3: IOPH,
4: IOPL,
5: RC,
},
}
export default PEL30
+21
View File
@@ -1,6 +1,9 @@
import EliteEDC from './EliteEDC/index'
import EliteEIS from './EliteEIS/index'
import EliteTrigger from './EliteTrigger/index'
import CPG from './CPG/index'
import PEL20 from './PEL_2_0/index'
import PEL30 from './PEL_3_0/index'
import store from '@/store/index'
// object saving library name mapping table
@@ -11,6 +14,7 @@ const libraryNameMappingTable = {
'Elite_EDC_1.5': EliteEDC,
'Elite_EDC_1.5re': EliteEDC,
'Elite_EDC_1.5r2': EliteEDC,
'Elite_EDC_2.0': EliteEDC,
'Elite_BAT_1.0': EliteEDC,
EIS: EliteEIS,
'Elite_EIS_1.0': EliteEIS,
@@ -18,6 +22,9 @@ const libraryNameMappingTable = {
'Elite_EIS_MINI_1.0': EliteEIS,
'Elite_TRIG_0.1': EliteTrigger,
'Elite_MEGAFLY_0.1': null,
CPG: CPG,
'PEL_2.0': PEL20,
'PEL_3.0': PEL30,
}
// object saving serial number mapping table
@@ -29,6 +36,7 @@ const serialNumberMappingTable = {
6: EliteEDC, // EDC1.5
7: EliteEDC, // EDC1.5re
8: EliteEDC, // EDC1.5r2
9: EliteEDC, // EDC2.0
},
},
3: {
@@ -54,6 +62,19 @@ const serialNumberMappingTable = {
0: null, // MEAGFLY0.1
},
},
7: {
0: {
0: PEL20,
1: PEL20,
2: PEL30,
},
},
8: {
0: {
0: CPG,
1: CPG,
},
},
},
}
+3 -2
View File
@@ -100,16 +100,17 @@ const transFileSize = (fileSize) => {
}
const transTime = (microsecond) => {
const radix = 1e6 // 1s = 1e6 microsecond
if (microsecond === undefined || microsecond === 'None') {
return '0 s'
}
let result = ''
if (microsecond < 1000000) {
if (microsecond < radix) {
result = '~ 1 s'
} else {
let seconds = parseInt(microsecond / 1000000)
let seconds = parseInt(microsecond / radix)
if (seconds < 60) {
result = `${seconds} s`
+9 -4
View File
@@ -64,7 +64,12 @@ $icon-font-path: './../fonts/';
src: url('~@/fonts/inter/Inter-Regular.ttf') format('truetype');
}
// @font-face {
// font-family: 'Inter';
// src: url('~@/fonts/inter/Inter-Regular.ttf') format('truetype');
// }
@font-face {
font-family: 'Inter-Medium';
src: url('~@/fonts/inter/Inter-Medium.ttf') format('truetype');
}
@font-face {
font-family: 'Inter';
src: url('~@/fonts/inter/Inter-Medium.ttf') format('truetype');
}
@@ -26,7 +26,10 @@ const downloadActs = {
const meta = state.metaInfo
const device = state.downloadInfo.device
const channel = payload.channel
const timeRatio = 1e6
const timeRatio = (device[1] === 'PEL') ? 1e3 : 1e6
// console.log('timeRatio', timeRatio)
// console.log('meta.configuration.SAMPLE_RATE', meta.configuration.SAMPLE_RATE)
let sampleRate = null
let channelNum = 1
@@ -47,6 +50,8 @@ const downloadActs = {
} else {
sampleRate = parseInt(meta.configuration.SAMPLE_RATE) / 10
}
} else if (device[1] === 'PEL') {
sampleRate = 1
} else {
sampleRate = parseInt(meta.configuration.SAMPLE_RATE) / 10
}
@@ -85,7 +90,10 @@ const downloadActs = {
const idNums = rawData.length
// estimate per raw_data contains x of samples
const samplePerRawData = parseInt(sampleNums / idNums)
let samplePerRawData = parseInt(sampleNums / idNums)
if (samplePerRawData === 0) {
samplePerRawData = 1
}
// estimate 9e5 rows need how many ID
const rawDataPerColumnTemp = parseInt((9e5 / parseInt(samplePerRawData)))
+35 -24
View File
@@ -137,12 +137,11 @@ const exportActs = {
titleArray.push([modeObj.channels.time.name, ` [${modeObj.channels.time.downloadUnit}]`].join(''))
// add each channel name & unit
for (const channel in downloadInfo.channelInfo) {
for (const channel of downloadInfo.channel) {
const name = modeObj.channels[channel]?.name
const unit = modeObj.channels[channel]?.downloadUnit && ' [' + modeObj.channels[channel]?.downloadUnit + ']'
titleArray.push([name, unit].join(''))
}
// repeat channel by cycle
const repeatArrayByCycle = repeat(titleArray, maxCycle)
titleString += repeatArrayByCycle.join(',') + '\r\n'
@@ -186,30 +185,42 @@ const exportActs = {
const columnArray = [...Array(downloadInfo.maxColumns).keys()]
for (const index in columnArray) {
for (const [chIndex, channel] of channels.entries()) {
const dataBuffer = downloadInfo.channelInfo[channel].downloadDataBuffer
if (dataBuffer[index][row] === undefined) {
if (downloadInfo.format === 'csv-edf' && payload.last) {
dataBuffer[index][row] = []
if (row === 0) {
break
}
if (chIndex === 0) {
dataBuffer[index][row].push((parseFloat(dataBuffer[index][row - 1][0]) + (downloadInfo.channelInfo[channel].timeInterval / 1e6)).toFixed(6))
}
dataBuffer[index][row].push(dataBuffer[index][row - 1][1])
rowData.push(...dataBuffer[index][row])
} else {
if (chIndex === 0) {
rowData.push(...['', ''])
} else {
rowData.push('')
}
if (downloadInfo.channelInfo[channel].type === 'formula') {
const formulaTarget = downloadInfo.channelInfo[channel].formulaTarget
const formula = downloadInfo.channelInfo[channel].formula
if (formulaTarget.length === 2) {
const dataBuffer1 = downloadInfo.channelInfo[formulaTarget[0]].downloadDataBuffer
const dataBuffer2 = downloadInfo.channelInfo[formulaTarget[1]].downloadDataBuffer
const result = formula(dataBuffer1[index][row + 1], dataBuffer2[index][row + 1])
rowData.push(result)
}
} else {
if (chIndex === 0) {
rowData.push(dataBuffer[index][row], dataBuffer[index][row + 1])
}
if (downloadInfo.channelInfo[channel].type !== 'formula') {
const dataBuffer = downloadInfo.channelInfo[channel].downloadDataBuffer
if (dataBuffer[index][row] === undefined) {
if (downloadInfo.format === 'csv-edf' && payload.last) {
dataBuffer[index][row] = []
if (row === 0) {
break
}
if (chIndex === 0) {
dataBuffer[index][row].push((parseFloat(dataBuffer[index][row - 1][0]) + (downloadInfo.channelInfo[channel].timeInterval / 1e6)).toFixed(6))
}
dataBuffer[index][row].push(dataBuffer[index][row - 1][1])
rowData.push(...dataBuffer[index][row])
} else {
if (chIndex === 0) {
rowData.push(...['', ''])
} else {
rowData.push('')
}
}
} else {
rowData.push(dataBuffer[index][row + 1])
if (chIndex === 0) {
rowData.push(dataBuffer[index][row], dataBuffer[index][row + 1])
} else {
rowData.push(dataBuffer[index][row + 1])
}
}
}
}