From 9b88dd87716672f833776f3e8294bfa3a0a35b6d Mon Sep 17 00:00:00 2001 From: wu58430 <wu58430@126.com> Date: Mon, 8 Jan 2024 11:46:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0eeprom=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/workspace.xml | 61 +- MDC_WRITE/MDC.txt | 15 - MDC_WRITE/main.py | 583 ++++++++++-------- README.md | 12 + app/menu.c | 29 +- chinese.h | 3 + main.c | 10 +- settings.c | 9 +- settings.h | 18 +- ui/menu.c | 25 +- ui/menu.h | 12 +- ui/welcome.c | 24 +- uv-k5font/uv-k5font_full/ALL_IN.txt | 4 +- .../Testing/Temporary/LastTest.log | 4 +- uv-k5font/uv-k5font_full/name_out.txt | 4 +- uv-k5font/uv-k5font_full/name_tmp.txt | 4 +- version.c | 2 +- 17 files changed, 471 insertions(+), 348 deletions(-) delete mode 100644 MDC_WRITE/MDC.txt diff --git a/.idea/workspace.xml b/.idea/workspace.xml index a13d968..2609ae0 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -20,11 +20,14 @@ </configurations> </component> <component name="ChangeListManager"> - <list default="true" id="cea36e80-e289-4d69-9030-7186d540ac0e" name="更改" comment="减少eeprom延时"> + <list default="true" id="cea36e80-e289-4d69-9030-7186d540ac0e" name="更改" comment="修正MDC联系人地址"> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/Makefile" beforeDir="false" afterPath="$PROJECT_DIR$/Makefile" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/main.c" beforeDir="false" afterPath="$PROJECT_DIR$/main.c" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/radio.c" beforeDir="false" afterPath="$PROJECT_DIR$/radio.c" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/MDC_WRITE/MDC.txt" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/MDC_WRITE/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/MDC_WRITE/main.py" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/ui/menu.c" beforeDir="false" afterPath="$PROJECT_DIR$/ui/menu.c" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/ui/menu.h" beforeDir="false" afterPath="$PROJECT_DIR$/ui/menu.h" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/ui/welcome.c" beforeDir="false" afterPath="$PROJECT_DIR$/ui/welcome.c" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/version.c" beforeDir="false" afterPath="$PROJECT_DIR$/version.c" afterDir="false" /> </list> <option name="SHOW_DIALOG" value="false" /> <option name="HIGHLIGHT_CONFLICTS" value="true" /> @@ -73,27 +76,27 @@ <option name="hideEmptyMiddlePackages" value="true" /> <option name="showLibraryContents" value="true" /> </component> - <component name="PropertiesComponent"><![CDATA[{ - "keyToString": { - "ASKED_ADD_EXTERNAL_FILES": "true", - "RunOnceActivity.OpenProjectViewOnStart": "true", - "RunOnceActivity.ShowReadmeOnStart": "true", - "RunOnceActivity.cidr.known.project.marker": "true", - "SHARE_PROJECT_CONFIGURATION_FILES": "true", - "WebServerToolWindowFactoryState": "false", - "cf.first.check.clang-format": "false", - "cidr.known.project.marker": "true", - "last_opened_file_path": "C:/Users/RUPC/Desktop/UV-K6/uv-k5-firmware-chinese", - "node.js.detected.package.eslint": "true", - "node.js.detected.package.tslint": "true", - "node.js.selected.package.eslint": "(autodetect)", - "node.js.selected.package.tslint": "(autodetect)", - "nodejs_package_manager_path": "npm", - "settings.editor.selected.configurable": "language.cpp.clang-tidy", - "structure.view.defaults.are.configured": "true", - "vue.rearranger.settings.migration": "true" + <component name="PropertiesComponent">{ + "keyToString": { + "ASKED_ADD_EXTERNAL_FILES": "true", + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.cidr.known.project.marker": "true", + "SHARE_PROJECT_CONFIGURATION_FILES": "true", + "WebServerToolWindowFactoryState": "false", + "cf.first.check.clang-format": "false", + "cidr.known.project.marker": "true", + "last_opened_file_path": "C:/Users/RUPC/Desktop/UV-K6/uv-k5-firmware-chinese", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "language.cpp.clang-tidy", + "structure.view.defaults.are.configured": "true", + "vue.rearranger.settings.migration": "true" } -}]]></component> +}</component> <component name="RecentsManager"> <key name="CopyFile.RECENT_KEYS"> <recent name="C:\Users\RUPC\Desktop\UV-K6\uv-k5-firmware-chinese" /> @@ -103,7 +106,7 @@ <recent name="C:\Users\RUPC\Desktop\UV-K6\uv-k5-firmware-chinese\app" /> </key> </component> - <component name="RunManager" selected="Makefile 目标.all"> + <component name="RunManager" selected="Makefile 目标.flash"> <configuration name="all" type="MAKEFILE_TARGET_RUN_CONFIGURATION" factoryName="Makefile" temporary="true"> <makefile filename="$PROJECT_DIR$/Makefile" target="all" workingDirectory="" arguments=""> <envs /> @@ -191,10 +194,10 @@ </list> <recent_temporary> <list> - <item itemvalue="Makefile 目标.all" /> <item itemvalue="Makefile 目标.flash" /> - <item itemvalue="Makefile 目标.clean" /> + <item itemvalue="Makefile 目标.all" /> <item itemvalue="Makefile 目标.build" /> + <item itemvalue="Makefile 目标.clean" /> <item itemvalue="Makefile 目标.debug" /> </list> </recent_temporary> @@ -264,6 +267,10 @@ <workItem from="1704370562673" duration="1618000" /> <workItem from="1704421657950" duration="14943000" /> <workItem from="1704442479624" duration="15616000" /> + <workItem from="1704611227205" duration="7887000" /> + <workItem from="1704636744423" duration="1043000" /> + <workItem from="1704681883948" duration="331000" /> + <workItem from="1704682476299" duration="8000" /> </task> <task id="LOCAL-00059" summary="写频"> <created>1701739409050</created> diff --git a/MDC_WRITE/MDC.txt b/MDC_WRITE/MDC.txt deleted file mode 100644 index 826837e..0000000 --- a/MDC_WRITE/MDC.txt +++ /dev/null @@ -1,15 +0,0 @@ -542B BG2FZV UVK6 SB -5438 BG2FZV IS A SB -4242 I AM SO STUPID -2B54 I AM A PIG -2B2B PIG I AM HA -3838 BG2FZV IS DSB -5454 WO SHI SHA BI -1234 zhu nao wo shi -7890 ~!@#$%^&*()_+/ -1111 niu bi wo cao -2222 sha zi bu hui -3333 nao tan -4444 chun zhu tou -5555 xiao si wo le -6666 ji ni tai mei diff --git a/MDC_WRITE/main.py b/MDC_WRITE/main.py index 981580a..9718037 100644 --- a/MDC_WRITE/main.py +++ b/MDC_WRITE/main.py @@ -1,23 +1,14 @@ -import sys -import serial.tools.list_ports -import re import serial -max_contact=15 -line_count=0 -MDC_ADD= [ 0x1D48, 0x1D88, 0x1DC8,0x1F08] -MDC_NUM_ADD=0X1D00 -file_out="MDC.txt" +from PyQt5.QtCore import QTimer +from PyQt5.QtWidgets import QMainWindow, QPushButton, QFileDialog, QLabel, QRadioButton, QMessageBox, QComboBox, \ + QProgressBar +from PyQt5.QtWidgets import QApplication +import sys +from PyQt5.QtGui import QImage, QPixmap, QColor +resized_image=None +cal_bin=1 com_open="" - - -def payload_xor(payload): - XOR_ARRAY = bytes.fromhex('166c14e62e910d402135d5401303e980') - XOR_LEN = len(XOR_ARRAY) - - ba=bytearray(payload) - for i in range(0,len(ba)): - ba[i] ^= XOR_ARRAY[i%XOR_LEN] - return bytes(ba) +pixel_list =[] Crc16Tab = [0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290, 45419, 49548, 53677, 57806, 61935, 4657, 528, 12915, 8786, 21173, 17044, 29431, 25302, 37689, 33560, 45947, 41818, 54205, 50076, 62463, 58334, 9314, 13379, 1056, 5121, 25830, 29895, 17572, 21637, 42346, 46411, 34088, 38153, 58862, 62927, 50604, 54669, 13907, 9842, 5649, 1584, 30423, 26358, 22165, 18100, 46939, 42874, 38681, 34616, 63455, 59390, 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241, 10242, 14371, 51660, 55789, @@ -30,260 +21,334 @@ Crc16Tab = [0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 4129 6864, 10931, 14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 36297, 31782, 27655, 23652, 19525, 15522, 11395, 7392, 3265, 61215, 65342, 53085, 57212, 44955, 49082, 36825, 40952, 28183, 32310, 20053, 24180, 11923, 16050, 3793, 7920] +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() -def crc16_ccitt(data): - i2 = 0 - for i3 in range(0, len(data)): - out = Crc16Tab[((i2 >> 8) ^ data[i3]) & 255] - i2 = out ^ (i2 << 8) + self.initUI() - return 65535 & i2 -def convert_payload_to_hex(code): - payload_decoded = payload_xor(code[4:-4]) # 跳过头部和尾部的校验信息 - hex_payload = ' '.join(['{:02X}'.format(byte) for byte in payload_decoded]) - return hex_payload -def check_format(line): - pattern = r'^[0-9A-Fa-f]{4}\s[\x20-\x7E]{1,14}$' - match = re.match(pattern, line) - if match: - remaining_chars = 14 - len(match.group(0)) + 5 # 计算还需要多少个字符(14个字符长度减去前面已匹配的字符长度和空格) - line = line.rstrip() + ' ' * remaining_chars # 使用空格填充到14个字符长度 - return line + '\n' # 返回修改后的行,加上换行符 - else: - print("文件格式错误,请仔细阅读示例!") - return None + def initUI(self): + global cal_bin -def update_file(file_path): - updated_lines = [] - with open(file_path, 'r') as file: - lines = file.readlines() - for line in lines: - updated_line = check_format(line.strip()) - if updated_line is not None: - updated_lines.append(updated_line) + self.setWindowTitle("Image Processing") + self.setGeometry(100, 100, 50+50+256, 300) + + self.open_button = QPushButton("Open Image", self) + self.open_button.setGeometry(20, 20, 100, 30) + self.open_button.clicked.connect(self.open_image) + + self.process_button = QPushButton("Process Image", self) + self.process_button.setGeometry(20, 70, 120, 30) + self.process_button.clicked.connect(self.process_image) + self.process_button.setEnabled(False) + + self.label = QLabel(self) + self.label.setGeometry(50, 150, 256, 128) + + self.radioButton1 = QRadioButton("效果1", self) + self.radioButton2 = QRadioButton("效果2", self) + cal_bin = 1 + self.radioButton1.setGeometry(0, 100, 120, 30) + self.radioButton2.setGeometry(50, 100, 120, 30) + + self.radioButton1.setChecked(True) # 默认选中第一个单选按钮 + + self.radioButton1.toggled.connect(self.on_radio_button_toggled) + self.radioButton2.toggled.connect(self.on_radio_button_toggled) + + self.combo_box = QComboBox(self) + self.combo_box.setGeometry(20, 120, 200, 30) + self.populate_serial_ports() # Populate available serial ports + self.combo_box.currentIndexChanged.connect(self.on_combo_box_changed) + + self.timer = QTimer() + self.timer.timeout.connect(self.populate_serial_ports) + self.timer.start(500) # Refresh every 5 seconds (1000 milliseconds) + + self.progress_bar = QProgressBar(self) + self.progress_bar.setGeometry(50, 150, 200, 20) + self.progress_bar.setValue(0) + # ... (previous code remains the same) + + from PyQt5.QtWidgets import QComboBox + + class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + self.initUI() + + def initUI(self): + # ... (existing code) + + self.combo_box = QComboBox(self) + self.combo_box.setGeometry(20, 120, 200, 30) + self.populate_serial_ports() # Populate available serial ports + self.combo_box.currentIndexChanged.connect(self.on_combo_box_changed) + + def populate_serial_ports(self): + com_open = self.combo_box.currentText() + import serial.tools.list_ports + self.combo_box.clear() + ports = serial.tools.list_ports.comports() + for port in ports: + self.combo_box.addItem(port.device) + if com_open!="": + index = self.combo_box.findText(com_open) + if index >= 0: + self.combo_box.setCurrentIndex(index) else: - updated_lines.append(line) # 不符合条件的行保持不变 + com_open = "" - # 将修改后的行写回文件 - with open(file_path, 'w') as file: - file.writelines(updated_lines) + def qimage_to_gray_list(self,img): + if img.isNull(): + return None -def check_duplicates(file_path): - lines_seen = set() - line_number = 0 + width = img.width() + height = img.height() - with open(file_path, 'r') as file: - for line in file: - line_number += 1 - first_four = line[:4] - if first_four in lines_seen: - print(f"MDC ID不能重复!!") - print(f"重复发现在第 {line_number} 行: {first_four}") - input("按 Enter 键退出程序") + pixel_list = [] + for y in range(height): + for x in range(width): + gray_value = QColor(img.pixelColor(x, y)).lightness() + pixel_list.append(gray_value) - sys.exit() - else: - lines_seen.add(first_four) -def time_set(): - global com_open - with serial.Serial( com_open, 38400, timeout=1) as ser: + return pixel_list - settime = b'\xAB\xCD\x08\x00\x02\x69\x10\xE6\xAC\xD1\x79\x25\x9D\xAD\xDC\xBA' - ser.write(settime) - full_response = ser.read(128) - if len(full_response) == 0: - print("连接失败!") - input("按 Enter 键退出程序") - - sys.exit() -def read_eeprom_byte(add): - global com_open - with serial.Serial(com_open, 38400, timeout=1) as ser: - payload = b'\x1B\x05' + b'\x08\x00' + add.to_bytes(2, byteorder='little') + b'\x11\x00' + b'\x82\x40\x74\x65' - # 将 payload 中的最后四个字节替换为当前时间戳 - hex_string = ' '.join(['{:02X}'.format(byte) for byte in payload]) - crc = crc16_ccitt(payload) - payload = payload + bytes([crc & 0xFF, ]) + bytes([crc >> 8, ]) # swap bytes of crc to get little endian - message = b'\xAB\xCD' + b'\x0C\x00' + payload_xor(payload) + b'\xDC\xBA' - ser.write(message) - full_response = ser.read(128) - if len(full_response) == 0: - print("读取失败!") - input("按 Enter 键退出程序") - - sys.exit() - - full_response_hex = full_response.hex() - # 将16进制字符串转换为字节串 - full_response = bytes.fromhex(full_response_hex) - # 对payload部分进行解码,然后以两位十六进制输出 - - payload_decoded = convert_payload_to_hex(full_response) - return payload_decoded[24:26] -def read_eeprom(): - num_contact = int( read_eeprom_byte(MDC_NUM_ADD), 16) - if num_contact==0 or num_contact>max_contact: - print("手台并无设置联系人,请先写入联系人!") - input("按 Enter 键退出程序") - - sys.exit() - print("开始读取MDC联系人") - with open(file_out, 'w+') as file: + def on_combo_box_changed(self, index): global com_open - with serial.Serial(com_open, 38400, timeout=1) as ser: - a=0 - while a<num_contact: - add=MDC_ADD[a//4]+(a%4)*16 - a=a+1 - print(a*100/num_contact,end='%\n') - payload = b'\x1B\x05' + b'\x08\x00' +add.to_bytes(2, byteorder='little')+b'\x10\x00'+b'\x82\x40\x74\x65' - # 将 payload 中的最后四个字节替换为当前时间戳 - hex_string = ' '.join(['{:02X}'.format(byte) for byte in payload]) - crc = crc16_ccitt(payload) - payload = payload + bytes([crc & 0xFF,]) + bytes([crc>>8,]) #swap bytes of crc to get little endian - message = b'\xAB\xCD' + b'\x0C\x00' + payload_xor(payload) + b'\xDC\xBA' - ser.write(message) + com_open = self.combo_box.currentText() + + # Debugging: print selected serial port + print(f"Selected port: {com_open}") + def on_radio_button_toggled(self): + global cal_bin + global resized_image + global pixel_list + + sender = self.sender() + + if sender.isChecked(): + if sender == self.radioButton1: + self.radioButton2.setChecked(False) + if self.process_button.isEnabled() and cal_bin == 2: + binarized_image = self.binarize_image1(resized_image) + pixel_list=self.qimage_to_gray_list(binarized_image) + self.show_img(binarized_image) + cal_bin=1 + else: + self.radioButton1.setChecked(False) + if self.process_button.isEnabled() and cal_bin == 1: + binarized_image = self.binarize_image2(resized_image) + pixel_list=self.qimage_to_gray_list(binarized_image) + self.show_img(binarized_image) + cal_bin=2 + def open_image(self): + global resized_image + global cal_bin + global pixel_list + + options = QFileDialog.Options() + file_path, _ = QFileDialog.getOpenFileName(self, "Open Image File", "", "Image Files (*.jpg *.png *.bmp *.jpeg)", + options=options) + if file_path: + self.image_path = file_path + self.process_button.setEnabled(True) + try: + original_image = QImage(self.image_path) + resized_image = self.resize_image_qimage(original_image, 128, 64) + if cal_bin==1: + binarized_image = self.binarize_image1(resized_image) + else: + binarized_image = self.binarize_image2(resized_image) + + #binarized_image.save("C:/Users/RUPC/Desktop/3.jpg") + pixel_list=self.qimage_to_gray_list(binarized_image) + self.show_img(binarized_image) + + + # 设置 label 为主窗口的中央部件 + # self.setCentralWidget(label) + except Exception as e: + print("Exception occurred:", str(e)) + + def process_image(self): + global pixel_list + global com_open + + self.disable_all_widgets() + if self.time_set()==False: + self.enable_all_widgets() + self.progress_bar.setValue(0) + + return False + add=0x1E320 + num=128 + self.progress_bar.setValue(20) + + try: + with serial.Serial(com_open, 38400, timeout=1) as ser: + pass + for i in range(8): + add1=add-0x10000 + payload = b'\x38\x05' + b'\x8A\x00' + b'\x01\x00' + b'\x82\x00' + b'\x82\x40\x74\x65' + add1.to_bytes(2, byteorder='little') + for value in pixel_list[i*128:i*128+128]: + payload += value.to_bytes(1, byteorder='big') # 转换为字节并添加到 payload + + # 将 payload 中的最后四个字节替换为当前时间戳 + crc = self.crc16_ccitt(payload) + payload = payload + bytes([crc & 0xFF, ]) + bytes([crc >> 8, ]) # swap bytes of crc to get little endian + + message = b'\xAB\xCD' + b'\x8e\x00' + self.payload_xor(payload) + b'\xDC\xBA' + hex_payload = ' '.join(hex(byte) for byte in message) + print(hex_payload) + ser.write(message) + full_response = ser.read(128) + if len(full_response) == 0: + self.message('写入失败') + self.progress_bar.setValue(0) + self.enable_all_widgets() + return False; + add=add+128 + self.progress_bar.setValue(20+(i+1)*10) + self.message('写入成功') + self.progress_bar.setValue(0) + self.enable_all_widgets() + + + except serial.SerialException: + self.self.message('写入失败') + self.progress_bar.setValue(0) + self.enable_all_widgets() + return False; + + + + def disable_all_widgets(self): + for widget in self.findChildren((QComboBox, QPushButton,QRadioButton)): + widget.setEnabled(False) + + def enable_all_widgets(self): + for widget in self.findChildren((QComboBox, QPushButton,QRadioButton)): + widget.setEnabled(True) + def show_img(self,binarized_image): + pixmap = QPixmap.fromImage(self.resize_image_qimage(binarized_image, 256, 128)) + self.label.setPixmap(pixmap) + def binarize_image1(self, original_image): + binarized_image = original_image.convertToFormat(QImage.Format_Mono) + return binarized_image + + def otsu_threshold(self,qimage): + # Convert QImage to grayscale + gray_qimage = qimage.convertToFormat(QImage.Format_Grayscale8) + + # Calculate histogram + histogram = [0] * 256 + total_pixels = gray_qimage.width() * gray_qimage.height() + + for y in range(gray_qimage.height()): + for x in range(gray_qimage.width()): + pixel = QColor(gray_qimage.pixel(x, y)) + histogram[pixel.red()] += 1 + + # Compute Otsu's threshold + sum_total = 0 + for i in range(256): + sum_total += i * histogram[i] + + sumB = 0 + wB = 0 + maximum = 0.0 + threshold = 0 + + for i in range(256): + wB += histogram[i] + if wB == 0: + continue + wF = total_pixels - wB + if wF == 0: + break + sumB += i * histogram[i] + mB = sumB / wB + mF = (sum_total - sumB) / wF + between = wB * wF * (mB - mF) * (mB - mF) + if between >= maximum: + threshold = i + maximum = between + + return threshold + def binarize_image2(self, qimage): + threshold = self.otsu_threshold(qimage) + + # Convert QImage to grayscale + gray_qimage = qimage.convertToFormat(QImage.Format_Grayscale8) + + # Apply Otsu's thresholding + for y in range(gray_qimage.height()): + for x in range(gray_qimage.width()): + pixel = QColor(gray_qimage.pixel(x, y)) + if pixel.red() > threshold: + gray_qimage.setPixel(x, y, QColor(255, 255, 255).rgb()) # White pixel + else: + gray_qimage.setPixel(x, y, QColor(0, 0, 0).rgb()) # Black pixel + + return gray_qimage + + def resize_image_qimage(self, image,width,high): + + + # 缩放图像 + resized_image = image.scaled(width, high) + + return resized_image + + def payload_xor(self,payload): + XOR_ARRAY = bytes.fromhex('166c14e62e910d402135d5401303e980') + XOR_LEN = len(XOR_ARRAY) + + ba = bytearray(payload) + for i in range(0, len(ba)): + ba[i] ^= XOR_ARRAY[i % XOR_LEN] + return bytes(ba) + + def crc16_ccitt(self,data): + i2 = 0 + for i3 in range(0, len(data)): + out = Crc16Tab[((i2 >> 8) ^ data[i3]) & 255] + i2 = out ^ (i2 << 8) + + return 65535 & i2 + + def convert_payload_to_hex(self,code): + payload_decoded = self.payload_xor(code[4:-4]) # 跳过头部和尾部的校验信息 + hex_payload = ' '.join(['{:02X}'.format(byte) for byte in payload_decoded]) + return hex_payload + def message(self,text): + msg_box = QMessageBox() + msg_box.setWindowTitle("提示") + msg_box.setText(text) + msg_box.setIcon(QMessageBox.Critical) + msg_box.setStandardButtons(QMessageBox.Ok) + msg_box.exec() + def time_set(self): + global com_open + try: + with serial.Serial(com_open, 38400, timeout=1) as ser: + settime = b'\xAB\xCD\x08\x00\x02\x69\x10\xE6\xAC\xD1\x79\x25\x9D\xAD\xDC\xBA' + ser.write(settime) full_response = ser.read(128) if len(full_response) == 0: - print("读取失败!") - input("按 Enter 键退出程序") - - sys.exit() - - full_response_hex = full_response.hex() - # 将16进制字符串转换为字节串 - full_response = bytes.fromhex(full_response_hex) - # 对payload部分进行解码,然后以两位十六进制输出 - - payload_decoded = convert_payload_to_hex(full_response) - i=0 - # 将print的输出定向到文件中 - for element in payload_decoded.split(' ')[8:]: - i = i + 1 - if i == 3: - file.write(' ') - if i >= 3: - file.write(chr(int(element, 16))) - else: - file.write(element.upper()) - file.write('\n') - print("读取成功,联系人保存至 MDC.txt") - return True -def write_eeprom_byte(add,num): - global com_open - with serial.Serial(com_open, 38400, timeout=1) as ser: - payload = b'\x1D\x05' + b'\x09\x00' + add.to_bytes(2, - byteorder='little') + b'\x0F\x00' + b'\x82\x40\x74\x65' + num.to_bytes(1, byteorder='big') - # 将 payload 中的最后四个字节替换为当前时间戳 - crc = crc16_ccitt(payload) - payload = payload + bytes([crc & 0xFF, ]) + bytes([crc >> 8, ]) # swap bytes of crc to get little endian - message = b'\xAB\xCD' + b'\x0D\x00' + payload_xor(payload) + b'\xDC\xBA' - ser.write(message) - - full_response = ser.read(128) - if len(full_response) == 0: - print("写入失败!") - input("按 Enter 键退出程序") - - sys.exit() -def write_eeprom_select(a,my_str): - global com_open - with serial.Serial(com_open, 38400, timeout=1) as ser: - add = MDC_ADD[a // 4] + (a % 4) * 16 - payload_data = ''.join(my_str).encode('utf-8') - hex1 = int(payload_data[0:2], 16) - hex2 = int(payload_data[2:4], 16) - payload_data = bytearray([hex1, hex2]) + payload_data[5:] - payload = b'\x1D\x05' + b'\x18\x00' + add.to_bytes(2, - byteorder='little') + b'\x10\x00' + b'\x82\x40\x74\x65' + payload_data - # 将 payload 中的最后四个字节替换为当前时间戳 - crc = crc16_ccitt(payload) - payload = payload + bytes([crc & 0xFF, ]) + bytes([crc >> 8, ]) # swap bytes of crc to get little endian - message = b'\xAB\xCD' + b'\x1C\x00' + payload_xor(payload) + b'\xDC\xBA' - ser.write(message) - - full_response = ser.read(128) - if len(full_response) == 0: - print("写入失败!") - input("按 Enter 键退出程序") - - sys.exit() -def deal_blank_line(): - global line_count # 声明 line_count 是全局变量 - with open(file_out, 'r') as file: - lines = file.readlines() - with open(file_out, 'w') as file: - for line in lines: - if line.strip(): - file.write(line) - with open(file_out, 'r') as file: - line_count = sum(1 for line in file) - if line_count==0: - print("请填写MDC联系人!") - input("按 Enter 键退出程序") - - sys.exit() - elif line_count>max_contact: - print("MDC联系人数量最大为",max_contact) - - -def write_eeprom(): - print("正在将MDC.txt写入到手台中") - global line_count # 声明 line_count 是全局变量 - a=0 - deal_blank_line() - update_file(file_out) - with open(file_out, 'r') as file: - for line in file: - add = MDC_ADD[a // 4] + (a % 4) * 16 - my_str = [] - my_str.append(line.replace('\n', '')) # 去除行尾的换行符 - write_eeprom_select(a,my_str) - print((a+1) * 100 / line_count, end='%\n') - a = a + 1 - if a==line_count: - break - - write_eeprom_byte(MDC_NUM_ADD,line_count) - print("写入成功") - return True - -# def main(): + self.populate_serial_ports() # Populate available serial ports + self.message("连接失败") + return False # Connection failed due to exception + except serial.SerialException: + self.message("连接失败") + return False # Connection failed due to exception if __name__ == "__main__": - available_ports = list(serial.tools.list_ports.comports()) - - if available_ports: - print("可用串口:") - for port in available_ports: - print(port.device) - else: - print("没有发现可用串口。") - com_open=input("输入串口(例:COM4):") - value=-1 - print("第一次使用MDC联系人请先写入联系人!!") - while value!=0 and value!=1: - value = int(input("写入(0)或读取(1)联系人:")) # 获取用户输入的整数值 - - if value == 0: - time_set() - write_eeprom() - elif value == 1: - time_set() - read_eeprom() - else: - value = int(input("输入无效!\n输入(0/1)来(写入/读取)联系人:")) # 获取用户输入的整数值 - input("按 Enter 键退出程序") - -# main() - - - -# code =[0xAB,0xCD,0x6C,0x00,0x0B,0x69,0x7C,0xE6,0x5E,0x9F,0x6D,0x41,0xBF,0x61,0xA1,0x25,0x13,0x02,0xE8,0x80,0x16,0x93,0x15,0xE2,0xD1,0x91,0x0D,0x44,0x20,0x36,0xD5,0x41,0x13,0x03,0x24,0x80,0x16,0xA1,0xDB,0x29,0xD1,0x6E,0x0D,0x40,0xDE,0xCA,0x2A,0xBF,0x13,0x00,0xE1,0x80,0x16,0x6D,0x14,0xE6,0xD1,0x6E,0xF2,0xBF,0xDE,0xCA,0x2A,0xBF,0x12,0x03,0x16,0x7F,0xE9,0x93,0xEB,0x19,0x2E,0x91,0x0D,0x40,0xDE,0xCA,0x2A,0xBF,0x42,0x56,0xA8,0xCE,0x45,0x24,0x51,0xA8,0x69,0x91,0x0D,0x40,0x21,0x35,0xD5,0x40,0x46,0x55,0xC4,0xCB,0x23,0x6C,0x14,0xE6,0x2E,0x91,0x0D,0x40,0x21,0x35,0xD5,0x40,0x79,0x5A,0xDC,0xBA] -# # code=[0xAB, 0xCD, 0x1C, 0x00, 0x0B, 0x69, 0x0C, 0xE6, 0xCE, 0x80, 0x1D, 0x40, 0xBF, 0x61, 0xA1, 0x25, 0xEC, 0xFC, 0x16, 0x7F, 0xE9, 0x93, 0xEB, 0x19, 0xD1, 0x6E, 0xF2, 0xBF, 0xDE, 0xCA, 0x2A, 0xBF, 0xCF, 0x04, 0xDC, 0xBA] -# payload_decoded = convert_payload_to_hex(code) # 跳过头部和尾部的校验信息 -# hex_payload = ' '.join(['{:02X}'.format(byte) for byte in payload_decoded]) -# print(hex_payload) - + app = QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec_()) diff --git a/README.md b/README.md index 30db708..15e6c24 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,18 @@ * 使用 EXIT 停止扫描时还原初始频率/频道,使用 MENU 按钮记住上次找到的传输 +# Eeprom分布说明: +* **前8K**基本不变 +* **0X1D00~0X1E00、0X1F90~0X1FF0** 22个MDC联系人,**0X1FFF**存放联系人数量 +* **0X0E92、0X0E91** MDC联系人高低8bit +* +**扩容版(K)**: +* **0x2000~1E31C** 中文字库(三个字库大小为:40960、40960、33564) +* **0x1E320~0x1E332** 开机字符1 ,**1xE31E** 存放长度 +* **0x1E333~0x1E345** 开机字符2 ,**0x1E31F** 存放长度 +* **0x1E350~0X1E450** 开机画面 + + # 示例 diff --git a/app/menu.c b/app/menu.c index a41cb03..2ee8593 100644 --- a/app/menu.c +++ b/app/menu.c @@ -184,12 +184,13 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax) { *pMin = 0; *pMax = ARRAY_SIZE(gSubMenu_ROGER) - 1; break; +#if ENABLE_CHINESE_FULL==4 -// case MENU_PONMSG: -// *pMin = 0; -// *pMax = ARRAY_SIZE(gSubMenu_OFF_ON) - 1; -// break; - + case MENU_PONMSG: + *pMin = 0; + *pMax = ARRAY_SIZE(gSubMenu_PONMSG) - 1; + break; +#endif case MENU_R_DCS: case MENU_T_DCS: *pMin = 0; @@ -697,10 +698,12 @@ void MENU_AcceptSetting(void) { } return; #endif -// case MENU_PONMSG: -// gEeprom.POWER_ON_DISPLAY_MODE = gSubMenuSelection; -// break; +#if ENABLE_CHINESE_FULL==4 + case MENU_PONMSG: + gEeprom.POWER_ON_DISPLAY_MODE = gSubMenuSelection; + break; +#endif case MENU_ROGER: gEeprom.ROGER = gSubMenuSelection; break; @@ -1076,11 +1079,11 @@ void MENU_ShowCurrentSetting(void) { case MENU_D_LIVE_DEC: gSubMenuSelection = gSetting_live_DTMF_decoder; break; - -// case MENU_PONMSG: -// gSubMenuSelection = gEeprom.POWER_ON_DISPLAY_MODE; -// break; - +#if ENABLE_CHINESE_FULL==4 + case MENU_PONMSG: + gSubMenuSelection = gEeprom.POWER_ON_DISPLAY_MODE; + break; +#endif case MENU_ROGER: gSubMenuSelection = gEeprom.ROGER; break; diff --git a/chinese.h b/chinese.h index 9b863c5..1edacbb 100644 --- a/chinese.h +++ b/chinese.h @@ -170,6 +170,7 @@ #define 省电模式 "\x88\xD1\x81\x1C\x95\xE1\x81\xAA" #define 麦克风增益 "\x83\x05\x83\x70\x80\xAE\x97\x51\x8D\x26" #define 信道显示模式 "\x89\x89\x92\xC8\x88\xE5\x80\xDF\x95\xE1\x81\xAA" +#define 开机显示 "\x80\x56\x81\xD9\x88\xE5\x80\xDF" #define 自动背光 "\x82\x5B\x81\xAF\x88\xC8\x82\x08" #define 背光亮度 "\x88\xC8\x82\x08\x89\xEA\x89\xEC" #define 首尾音 "\x8A\x1E\x84\xE1\x8A\x01" @@ -273,6 +274,8 @@ #define 模拟亚音 "\x95\xE1\x83\x48\x81\xD2\x8A\x01" #define 数字亚音 "\x95\x19\x82\xBB\x81\xD2\x8A\x01" +#define 图片 "\x86\x4C\x80\x92" +#define 信息 "\x89\x89\x8C\x8C" #endif #endif //UV_K5_FIRMWARE_CUSTOM_0_17_CHINESE_H diff --git a/main.c b/main.c index cb996b6..e442d73 100644 --- a/main.c +++ b/main.c @@ -293,7 +293,7 @@ void Main(void) { //BootMode = BOOT_GetMode(); // if (BootMode == BOOT_MODE_F_LOCK) - gMenuListCount = 45; + gMenuListCount = 46; // wait for user to release all butts before moving on @@ -316,8 +316,14 @@ void Main(void) { UI_DisplayWelcome(); boot_counter_10ms = 250; + while (boot_counter_10ms > 0) { - if (KEYBOARD_Poll() == KEY_EXIT) { // halt boot beeps + + if (KEYBOARD_Poll() == KEY_EXIT + #if ENABLE_CHINESE_FULL==4 + ||gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_NONE + #endif + ) { // halt boot beeps boot_counter_10ms = 0; break; } diff --git a/settings.c b/settings.c index 8f281da..bc1a767 100644 --- a/settings.c +++ b/settings.c @@ -120,8 +120,9 @@ void SETTINGS_InitEEPROM(void) // gEeprom.KEY_2_LONG_PRESS_ACTION = (Data[4] < ACTION_OPT_LEN) ? Data[4] : ACTION_OPT_NONE; gEeprom.SCAN_RESUME_MODE = (Data[5] < 3) ? Data[5] : SCAN_RESUME_CO; // gEeprom.AUTO_KEYPAD_LOCK = (Data[6] < 2) ? Data[6] : false; -// gEeprom.POWER_ON_DISPLAY_MODE = (Data[7] < 4) ? Data[7] : POWER_ON_DISPLAY_MODE_MESSAGE; - +#if ENABLE_CHINESE_FULL==4 + gEeprom.POWER_ON_DISPLAY_MODE = (Data[7] < 4) ? Data[7] : POWER_ON_DISPLAY_MODE_NONE; +#endif // 0E98..0E9F EEPROM_ReadBuffer(0x0E98, Data, 8); memcpy(&gEeprom.POWER_ON_PASSWORD, Data, 4); @@ -537,7 +538,9 @@ void SETTINGS_SaveSettings(void) State[4] = 0;//gEeprom.KEY_2_LONG_PRESS_ACTION; State[5] = gEeprom.SCAN_RESUME_MODE; State[6] = 0;//gEeprom.AUTO_KEYPAD_LOCK; - State[7] = 0;//gEeprom.POWER_ON_DISPLAY_MODE; +#if ENABLE_CHINESE_FULL==4 + State[7] = gEeprom.POWER_ON_DISPLAY_MODE; +#endif EEPROM_WriteBuffer(0x0E90, State,8); memset(Password, 0xFF, sizeof(Password)); diff --git a/settings.h b/settings.h index e514ba2..4bdacbf 100644 --- a/settings.h +++ b/settings.h @@ -24,14 +24,16 @@ #include <helper/battery.h> #include "radio.h" #include <driver/backlight.h> +#if ENABLE_CHINESE_FULL==4 -//enum POWER_OnDisplayMode_t { -// POWER_ON_DISPLAY_MODE_NONE -//, -// POWER_ON_DISPLAY_MODE_MESSAGE, -//}; +enum POWER_OnDisplayMode_t { + POWER_ON_DISPLAY_MODE_NONE, + POWER_ON_DISPLAY_MODE_PIC, + POWER_ON_DISPLAY_MODE_MESSAGE + +}; typedef enum POWER_OnDisplayMode_t POWER_OnDisplayMode_t; - +#endif enum TxLockModes_t { F_LOCK_DEF, //all default frequencies + configurable F_LOCK_FCC, @@ -189,7 +191,9 @@ typedef struct { #if defined(ENABLE_ALARM) || defined(ENABLE_TX1750) ALARM_Mode_t ALARM_MODE; #endif - // POWER_OnDisplayMode_t POWER_ON_DISPLAY_MODE; +#if ENABLE_CHINESE_FULL==4 + POWER_OnDisplayMode_t POWER_ON_DISPLAY_MODE; +#endif ROGER_Mode_t ROGER; uint8_t REPEATER_TAIL_TONE_ELIMINATION; // uint8_t KEY_1_SHORT_PRESS_ACTION; diff --git a/ui/menu.c b/ui/menu.c index c3246ef..5e7e969 100644 --- a/ui/menu.c +++ b/ui/menu.c @@ -72,7 +72,9 @@ const t_menu_item MenuList[] = {/*"BatSav",*/ VOICE_ID_SAVE_MODE, MENU_SAVE, 省电模式}, // was "SAVE" {/*"Mic",*/ VOICE_ID_INVALID, MENU_MIC, 麦克风增益}, {/*"ChDisp",*/ VOICE_ID_INVALID, MENU_MDF, 信道显示模式}, // was "MDF" - // {/*"POnMsg",*/ VOICE_ID_INVALID, MENU_PONMSG ,开机显示}, +#if ENABLE_CHINESE_FULL==4 + {/*"POnMsg",*/ VOICE_ID_INVALID, MENU_PONMSG ,开机显示}, +#endif {/*"BackLt",*/ VOICE_ID_INVALID, MENU_ABR, 自动背光}, // was "ABR" {/*"BLMax",*/ VOICE_ID_INVALID, MENU_ABR_MAX, 背光亮度}, {/*"MDCID",*/ VOICE_ID_INVALID, MENU_MDC_ID, MDC_ID}, @@ -126,12 +128,19 @@ const t_menu_item MenuList[] = // {/*"",*/ VOICE_ID_INVALID, 0xff ,"\x00"} // end of list - DO NOT delete or move this this }; - - +#if ENABLE_CHINESE_FULL == 4 +const char gSubMenu_PONMSG[][5]={ + 关闭, + 图片, + 信息 +}; +#endif const uint8_t FIRST_HIDDEN_MENU_ITEM = MENU_F_LOCK; #if ENABLE_CHINESE_FULL != 4 const char gSubMenu_SFT_D[][10] =//4 #else + + const char gSubMenu_SFT_D[][16] =//4 #endif { @@ -928,12 +937,12 @@ void UI_DisplayMenu(void) { memcpy(String, Contact, 8); break; #endif -// case MENU_PONMSG: -// strcpy(String, gSubMenu_OFF_ON[gSubMenuSelection]); -// -// -// break; +#if ENABLE_CHINESE_FULL==4 + case MENU_PONMSG: + strcpy(String, gSubMenu_PONMSG[gSubMenuSelection]); + break; +#endif case MENU_ROGER: strcpy(String, gSubMenu_ROGER[gSubMenuSelection]); diff --git a/ui/menu.h b/ui/menu.h index 90acfb5..d817e88 100644 --- a/ui/menu.h +++ b/ui/menu.h @@ -106,7 +106,11 @@ enum #endif MENU_D_LIVE_DEC, - // MENU_PONMSG, +#if ENABLE_CHINESE_FULL==4 + +MENU_PONMSG, +#endif + MENU_ROGER, // MENU_VOL, //MENU_BAT_TXT, @@ -141,16 +145,22 @@ enum extern const uint8_t FIRST_HIDDEN_MENU_ITEM; extern const t_menu_item MenuList[]; +#if ENABLE_CHINESE_FULL==4 + +extern const char gSubMenu_PONMSG[3][5]; +#endif //extern const char gSubMenu_TXP[3][2];//5 #if ENABLE_CHINESE_FULL!=4 extern const char gSubMenu_SFT_D[3][10];//3 #else + extern const char gSubMenu_SFT_D[3][16];//3 #endif //extern const char gSubMenu_W_N[2][3];//7 #if ENABLE_CHINESE_FULL!=4 extern const char gSubMenu_OFF_ON[2][3];//4 + #else extern const char gSubMenu_OFF_ON[2][5];//4 #endif diff --git a/ui/welcome.c b/ui/welcome.c index a1c4f89..22f3a07 100644 --- a/ui/welcome.c +++ b/ui/welcome.c @@ -50,31 +50,41 @@ void UI_DisplayWelcome(void) { memset(gStatusLine, 0, sizeof(gStatusLine)); UI_DisplayClear(); + ST7565_BlitStatusLine(); // blank status line + ST7565_BlitFullScreen(); + if (gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_MESSAGE) { #if ENABLE_CHINESE_FULL == 4 uint8_t welcome_len[2]; EEPROM_ReadBuffer(0x1e31e, welcome_len, 2) ; welcome_len[0]=welcome_len[0]>18?0:welcome_len[0]; welcome_len[1]=welcome_len[1]>18?0:welcome_len[1]; - EEPROM_ReadBuffer(0x1e320, WelcomeString0, welcome_len[0]) ; EEPROM_ReadBuffer(0x1e333, WelcomeString1, welcome_len[1]); - UI_PrintStringSmall( WelcomeString0, 0, 127, 0); - UI_PrintStringSmall( WelcomeString1, 0, 127, 2); #else - EEPROM_ReadBuffer(0x0EB0, WelcomeString0, 16); EEPROM_ReadBuffer(0x0EC0, WelcomeString1, 16); - UI_PrintStringSmall(WelcomeString0, 0, 127, 0); - UI_PrintStringSmall(WelcomeString1, 0, 127, 2); + #endif + UI_PrintStringSmall( WelcomeString0, 0, 127, 0); + UI_PrintStringSmall( WelcomeString1, 0, 127, 2); sprintf(WelcomeString1, "%u.%02uV %u%%", gBatteryVoltageAverage / 100, gBatteryVoltageAverage % 100, BATTERY_VoltsToPercent(gBatteryVoltageAverage)); UI_PrintStringSmall(WelcomeString1, 0, 127, 4); - UI_PrintStringSmall(Version, 0, 127, 6); + } +#if ENABLE_CHINESE_FULL == 4 + else if(gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_PIC) + { + EEPROM_ReadBuffer( 0x1E350, gStatusLine, 128); + for (int i = 0; i < 7; ++i) EEPROM_ReadBuffer(0x1E350+128+128*i, &gFrameBuffer[i], 128); + + + } +#endif + ST7565_BlitStatusLine(); // blank status line ST7565_BlitFullScreen(); diff --git a/uv-k5font/uv-k5font_full/ALL_IN.txt b/uv-k5font/uv-k5font_full/ALL_IN.txt index eba8fc6..bf390b1 100644 --- a/uv-k5font/uv-k5font_full/ALL_IN.txt +++ b/uv-k5font/uv-k5font_full/ALL_IN.txt @@ -6997,4 +6997,6 @@ � �� �Q -���ǰ�ʰ������ +������ʾ +ͼƬ +��Ϣ diff --git a/uv-k5font/uv-k5font_full/cmake-build-debug/Testing/Temporary/LastTest.log b/uv-k5font/uv-k5font_full/cmake-build-debug/Testing/Temporary/LastTest.log index e0950f6..43abdaa 100644 --- a/uv-k5font/uv-k5font_full/cmake-build-debug/Testing/Temporary/LastTest.log +++ b/uv-k5font/uv-k5font_full/cmake-build-debug/Testing/Temporary/LastTest.log @@ -1,3 +1,3 @@ -Start testing: Dec 23 13:01 �й���ʱ�� +Start testing: Jan 08 10:58 �й���ʱ�� ---------------------------------------------------------- -End testing: Dec 23 13:01 �й���ʱ�� +End testing: Jan 08 10:58 �й���ʱ�� diff --git a/uv-k5font/uv-k5font_full/name_out.txt b/uv-k5font/uv-k5font_full/name_out.txt index 4640788..99d3ac4 100644 --- a/uv-k5font/uv-k5font_full/name_out.txt +++ b/uv-k5font/uv-k5font_full/name_out.txt @@ -6997,4 +6997,6 @@ \x9B\x70 \x9B\x71 \x9B\x72 -\x84\x6C\x88\xD9\x8C\x6C\x88\x18\x8F\x8C\x96\x27\x80\x07 +\x80\x56\x81\xD9\x88\xE5\x80\xDF +\x86\x4C\x80\x92 +\x89\x89\x8C\x8C diff --git a/uv-k5font/uv-k5font_full/name_tmp.txt b/uv-k5font/uv-k5font_full/name_tmp.txt index 4640788..99d3ac4 100644 --- a/uv-k5font/uv-k5font_full/name_tmp.txt +++ b/uv-k5font/uv-k5font_full/name_tmp.txt @@ -6997,4 +6997,6 @@ \x9B\x70 \x9B\x71 \x9B\x72 -\x84\x6C\x88\xD9\x8C\x6C\x88\x18\x8F\x8C\x96\x27\x80\x07 +\x80\x56\x81\xD9\x88\xE5\x80\xDF +\x86\x4C\x80\x92 +\x89\x89\x8C\x8C diff --git a/version.c b/version.c index 38e7a75..40d2bc7 100644 --- a/version.c +++ b/version.c @@ -4,7 +4,7 @@ #ifdef GIT_HASH #define VER GIT_HASH #else - #define VER "113" + #define VER "114TEST" #endif