增加eeprom说明

This commit is contained in:
wu58430 2024-01-08 11:46:18 +08:00
parent c69d3c5a96
commit 9b88dd8771
17 changed files with 471 additions and 348 deletions

61
.idea/workspace.xml generated
View file

@ -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">{
&quot;keyToString&quot;: {
&quot;ASKED_ADD_EXTERNAL_FILES&quot;: &quot;true&quot;,
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.cidr.known.project.marker&quot;: &quot;true&quot;,
&quot;SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;,
&quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
&quot;cf.first.check.clang-format&quot;: &quot;false&quot;,
&quot;cidr.known.project.marker&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;C:/Users/RUPC/Desktop/UV-K6/uv-k5-firmware-chinese&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;language.cpp.clang-tidy&quot;,
&quot;structure.view.defaults.are.configured&quot;: &quot;true&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}]]></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>

View file

@ -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

View file

@ -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_())

View file

@ -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** 开机画面
# 示例

View file

@ -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;

View file

@ -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

10
main.c
View file

@ -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;
}

View file

@ -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));

View file

@ -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;

View file

@ -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]);

View file

@ -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

View file

@ -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();

View file

@ -6997,4 +6997,6 @@
ף½
לא
Q
这是俺拾得嘞七
开机显示
图片
信息

View file

@ -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 中国标准时间

View file

@ -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

View file

@ -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

View file

@ -4,7 +4,7 @@
#ifdef GIT_HASH
#define VER GIT_HASH
#else
#define VER "113"
#define VER "114TEST"
#endif