Skip to content

Commit

Permalink
Merge pull request #101 from stache3000/uvmod_kitchen_K6_V3.00.15
Browse files Browse the repository at this point in the history
Partial mods port for firmware v3.00.15
  • Loading branch information
amnemonic authored Oct 19, 2023
2 parents e03fa19 + e351481 commit 2f7609b
Show file tree
Hide file tree
Showing 11 changed files with 350 additions and 0 deletions.
Binary file added uvmod_kitchen_v3.00.15/K6_V3.00.15.bin
Binary file not shown.
21 changes: 21 additions & 0 deletions uvmod_kitchen_v3.00.15/build.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@echo off
@rmdir /q /s temp 2>NUL
@mkdir temp

@echo Extracting firmare...
python qsfirm.py unpack K6_V3.00.15.bin temp\fw.dec.bin temp\fw.ver.bin

:: here comment or uncomment mods

python mod_custom_freq_ranges.py temp\fw.dec.bin
python mod_remove_tx_limits.py temp\fw.dec.bin
python mod_universal_version.py temp\fw.ver.bin
python mod_battery_icon.py temp\fw.dec.bin
python mod_increases_abr_values.py temp\fw.dec.bin
python mod_custom_steps.py temp\fw.dec.bin

:: end of mods

@echo Repacking firmware...
python qsfirm.py pack temp\fw.dec.bin temp\fw.ver.bin K6_V3.00.15-MODDED.bin

19 changes: 19 additions & 0 deletions uvmod_kitchen_v3.00.15/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

rm -rf temp 2>/dev/null
mkdir temp

python3 qsfirm.py unpack K6_V3.00.15.bin temp/fw.dec.bin temp/fw.ver.bin

# here comment or uncomment mods

python3 mod_custom_freq_ranges.py temp/fw.dec.bin
python3 mod_remove_tx_limits.py temp/fw.dec.bin
python3 mod_universal_version.py temp/fw.ver.bin
python3 mod_battery_icon.py temp/fw.dec.bin
python3 mod_increases_abr_values.py temp/fw.dec.bin
python3 mod_custom_steps.py temp/fw.dec.bin

# end of mods

python3 qsfirm.py pack temp/fw.dec.bin temp/fw.ver.bin K6_V3.00.15-MODDED.bin
19 changes: 19 additions & 0 deletions uvmod_kitchen_v3.00.15/mod_battery_icon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# the original battery icon looks stupid, with the bars starting on the left and the odd line art. this replaces it with a more familiar design.
# the two offsets used in fw[0xCF18+134:0xCF18+223] limit the data to just the battery bitmaps, while fw[0xCF18:0xCF18] contains the entire set of 8px symbols for future mods


##--------------------- do not modify below this line ---------------------------------------------------
import os,sys,struct
print('Running',os.path.basename(sys.argv[0]),'mod...')

fw = bytearray(open(sys.argv[1],'rb').read())

if fw[0xCF18+134:0xCF18+223] == b'>"\x7fAAAAAAAAAAAAAc\x00>"\x7fA]]AAAAAAAAAAc\x00>"\x7fA]]A]]AAAAAAAc\x00>"\x7fA]]A]]A]]AAAAc\x00>"\x7fA]]A]]A]]A]]Ac':
print('Patching battery icon data...')
fw[0xCF18+134:0xCF18+223] = b'>"cAAAAAAAAAAAAA\x7f\x00>"cAAAAAAAAAA]]Ac\x00>"cAAAAAAA]]A]]A\x7f\x00>"cAAAA]]A]]A]]A\x7f\x00>"cA]]A]]A]]A]]A\x7f'
else:
print('ERROR: Cant find data')
sys.exit(0)


open(sys.argv[1],'wb').write(fw)
59 changes: 59 additions & 0 deletions uvmod_kitchen_v3.00.15/mod_custom_freq_ranges.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# change below sets to new ones, values are in Hz
new_freq_low_limit = [18_000_000, 76_000_000, 136_000_000, 174_000_000, 350_000_000, 400_000_000, 470_000_000]
new_freq_high_limit = [75_999_900, 135_999_900, 173_999_900, 349_999_900, 399_999_900, 469_999_900, 1300_000_000]



##--------------------- do not modify below this line ---------------------------------------------------
import os,sys,struct

LOFREQ_FW_LOC = 0xEB30 #v3.00.15
HIFREQ_FW_LOC = 0xEB4C #v3.00.15

print('\n>>> Running',os.path.basename(sys.argv[0]),'mod...')

#prechecks
if len(new_freq_low_limit)!=7: print('Do not change number of entries! Exiting'); exit(0)
if len(new_freq_high_limit)!=7: print('Do not change number of entries! Exiting'); exit(0)


#read fw to buffer
fw = bytearray(open(sys.argv[1],'rb').read())

#Show old ranges
print('Replacing ranges:')
current_lo_limits = struct.unpack_from('<IIIIIII', fw, offset=LOFREQ_FW_LOC)
current_hi_limits = struct.unpack_from('<IIIIIII', fw, offset=HIFREQ_FW_LOC)
for i in range(7):
print('Range F{} {:>11} Hz -{:>11} Hz --> {:>11} Hz -{:>11} Hz'.format(i+1,
current_lo_limits[i]*10 ,
current_hi_limits[i]*10 ,
new_freq_low_limit[i] ,
new_freq_high_limit[i]
))






## REPLACE LOFREQ
if fw[LOFREQ_FW_LOC:LOFREQ_FW_LOC+(4*7)] == bytearray(struct.pack('<IIIIIII', *[5000000, 10800000, 13600000, 17400000, 35000000, 40000000, 47000000])):
print('LOFREQ table found, replacing...')
fw[LOFREQ_FW_LOC:LOFREQ_FW_LOC+(4*7)] = bytearray(struct.pack('<IIIIIII', *[i//10 for i in new_freq_low_limit]))
else:
print('Error, orginal LOFREQ table doesnt match default values. Wrong fw ver?')


## REPLACE HIFREQ
if fw[HIFREQ_FW_LOC:HIFREQ_FW_LOC+(4*7)] == bytearray(struct.pack('<IIIIIII', *[7600000, 13599990, 17399990, 34999990, 39999990, 46999990, 60000000])):
print('HIFREQ table found, replacing...')
fw[HIFREQ_FW_LOC:HIFREQ_FW_LOC+(4*7)] = bytearray(struct.pack('<IIIIIII', *[i//10 for i in new_freq_high_limit]))
else:
print('Error, orginal HIFREQ table doesnt match default values. Wrong fw ver?')




#write fw back
open(sys.argv[1],'wb').write(fw)
34 changes: 34 additions & 0 deletions uvmod_kitchen_v3.00.15/mod_custom_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# change below sets to new ones, values are in Hz
new_freq_steps = [2500, 5000, 6250, 10000, 12500, 25000, 8330]



##--------------------- do not modify below this line ---------------------------------------------------
import os,sys,struct
if len(new_freq_steps)!=7: print('Do not change number of entries'); exit(0)

print('Running',os.path.basename(sys.argv[0]),'mod...')

addr = 0xE170

fw = bytearray(open(sys.argv[1],'rb').read())
current_steps = struct.unpack_from('<HHHHHHH', fw, offset=addr)
print('Old freq steps:', [f'{i*10} Hz' for i in current_steps])


if fw[addr :addr+ 2] == bytearray(struct.pack('<H', 250)): fw[addr :addr+ 2] = struct.pack('<H',new_freq_steps[0]//10); print('.',end='')
if fw[addr+ 2:addr+ 4] == bytearray(struct.pack('<H', 500)): fw[addr+ 2:addr+ 4] = struct.pack('<H',new_freq_steps[1]//10); print('.',end='')
if fw[addr+ 4:addr+ 6] == bytearray(struct.pack('<H', 625)): fw[addr+ 4:addr+ 6] = struct.pack('<H',new_freq_steps[2]//10); print('.',end='')
if fw[addr+ 6:addr+ 8] == bytearray(struct.pack('<H',1000)): fw[addr+ 6:addr+ 8] = struct.pack('<H',new_freq_steps[3]//10); print('.',end='')
if fw[addr+ 8:addr+10] == bytearray(struct.pack('<H',1250)): fw[addr+ 8:addr+10] = struct.pack('<H',new_freq_steps[4]//10); print('.',end='')
if fw[addr+10:addr+12] == bytearray(struct.pack('<H',2500)): fw[addr+10:addr+12] = struct.pack('<H',new_freq_steps[5]//10); print('.',end='')
if fw[addr+12:addr+14] == bytearray(struct.pack('<H', 833)): fw[addr+12:addr+14] = struct.pack('<H',new_freq_steps[6]//10); print('.',end='')
print()


current_steps = struct.unpack_from('<HHHHHHH', fw, offset=addr)
print('New freq steps:', [f'{i*10} Hz' for i in current_steps])



open(sys.argv[1],'wb').write(fw)
21 changes: 21 additions & 0 deletions uvmod_kitchen_v3.00.15/mod_increases_abr_values.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# This mod allows you to increase the value of the ABR by 2 by 4 or by 8 , remove # at the beginning of the line , according to the value of interest


# multi=int(64) #
# multi=int(128) # (1 corresponds to 2 seconds, 2 corresponds to 4 seconds... up to 5, which corresponds to 10 seconds)
multi=int(192) # (1 corresponds to 4 seconds, 2 corresponds to 8 seconds... up to 5, which corresponds to 20 seconds)
# multi=int(256) # (1 corresponds to 8 seconds, 2 corresponds to 16 seconds... up to 5, which corresponds to 40 seconds)
##--------------------- do not modify below this line ---------------------------------------------------
import os,sys,struct
print('Running',os.path.basename(sys.argv[0]),'mod...')

fw = bytearray(open(sys.argv[1],'rb').read())

if fw[0x57A6] == 0x40 and fw[0x57A7] == 0x00 :
print('Doubling screen timeout values...')
fw[0x57A6:0x57A6+4] = struct.pack('<I',multi)
else:
print('ERROR: Cant find function')


open(sys.argv[1],'wb').write(fw)
42 changes: 42 additions & 0 deletions uvmod_kitchen_v3.00.15/mod_remove_tx_limits.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# change below sets to new ones, values are in Hz
tx_low_limit = 18_000_000
tx_high_limit = 1_300_000_000



##--------------------- do not modify below this line ---------------------------------------------------
import os,sys,struct

TXLOLIM_FW_LOC = 0x1438
TXHILIM_FW_LOC = 0x143C
BLOCKFN_FW_LOC = 0x173A # CMP R2, #0xCF

print('\n>>> Running',os.path.basename(sys.argv[0]),'mod...')
fw = bytearray(open(sys.argv[1],'rb').read())


print('Changing TX limit: {} Hz - {} Hz --> {} Hz - {} Hz'.format(
struct.unpack_from('<I', fw, offset=TXLOLIM_FW_LOC)[0]*10,
struct.unpack_from('<I', fw, offset=TXHILIM_FW_LOC)[0]*10,
tx_low_limit,
tx_high_limit
))


fw[TXLOLIM_FW_LOC:TXLOLIM_FW_LOC+4] = struct.pack('<I',tx_low_limit//10)
fw[TXHILIM_FW_LOC:TXHILIM_FW_LOC+4] = struct.pack('<I',tx_high_limit//10)



print('Patching tx_not_allowed() funtion...')
if fw[BLOCKFN_FW_LOC:BLOCKFN_FW_LOC+2] == b'\xcf\x2a':
fw[BLOCKFN_FW_LOC:BLOCKFN_FW_LOC+2] = b'\x5d\xe0'
else:
print('ERROR: Cant find function')





open(sys.argv[1],'wb').write(fw)
print('Done')
13 changes: 13 additions & 0 deletions uvmod_kitchen_v3.00.15/mod_universal_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#nothing to configure here

##--------------------- do not modify below this line ---------------------------------------------------
import os,sys,struct
print('\n>>> Running',os.path.basename(sys.argv[0]),'mod...')

fw = bytearray(open(sys.argv[1],'rb').read())

print('Setting universal version...', end=' ')
fw[0x0:0x0+1] = b'*'

open(sys.argv[1],'wb').write(fw)
print('Done')
99 changes: 99 additions & 0 deletions uvmod_kitchen_v3.00.15/qsfirm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import sys,os


# Handle arguments
if len(sys.argv)!=5 or sys.argv[1] not in ['unpack','pack'] : print(f'''
Usage: {os.path.basename(sys.argv[0])} unpack <encoded_firmware_in.bin> <decoded_firmware_out.bin> <versionfile_out.bin>
{os.path.basename(sys.argv[0])} pack <decoded_firmware_in.bin> <versionfile_in.bin> <encoded_firmware_out.bin>
''') ; exit(1)

# CRC Routines
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,
59790, 63919, 35144, 39273, 43274, 47403, 23285, 19156, 31415, 27286, 6769, 2640,14899, 10770, 56317, 52188, 64447, 60318, 39801, 35672, 47931, 43802, 27814, 31879,
19684, 23749, 11298, 15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395,36200, 40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 61374,
57309, 53244, 48923, 44858, 40793, 36728, 37256, 33193, 45514, 41451, 53516, 49453, 61774, 57711, 4224, 161, 12482, 8419, 20484, 16421, 28742, 24679, 33721, 37784, 41979,
46042, 49981, 54044, 58239, 62302, 689, 4752, 8947, 13010, 16949, 21012, 25207, 29270, 46570, 42443, 38312, 34185, 62830, 58703, 54572, 50445, 13538, 9411, 5280, 1153, 29798,
25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231, 63358, 50973, 55100, 9939, 14066, 1681, 5808, 26199, 30326, 17941, 22068, 55628, 51565, 63758, 59695, 39368,
35305, 47498, 43435, 22596, 18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093, 56156, 60223, 64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801,
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]

def crc16_ccitt(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 crc16_ccitt_le(data):
crc = crc16_ccitt(data)
return bytes([crc & 0xFF,]) + bytes([crc>>8,])


# Encoding/decoding algo
def firmware_xor(fwcontent):
XOR_ARRAY = bytes.fromhex('4722c0525d574894b16060db6fe34c7cd84ad68b30ec25e04cd9007fbfe35405e93a976bb06e0cfbb11ae2c9c15647e9baf142b6675f0f96f7c93c841b26e14e3b6f66e6a06ab0bfc6a5703aba189e271a535b71b1941e18f2d6810222fd5a2891dbba5d64c6fe86839c501c730311d6af30f42c77b27dbb3f29285722d6928b')
XOR_LEN = len(XOR_ARRAY)

ba=bytearray(fwcontent)
for i in range(0,len(ba)):
ba[i] ^= XOR_ARRAY[i%XOR_LEN]
return bytes(ba)



#-------- main ------------------
if sys.argv[1]=='unpack':
encoded_firmware = open(sys.argv[2],'rb').read()
#check CRC, information only
if crc16_ccitt_le(encoded_firmware[:-2]) == encoded_firmware[-2:]:
print('CRC OK')
else:
print('CRC MISMATCH!')

decoded_firmware = firmware_xor(encoded_firmware[:-2])

#save decoded firmware to file
open(sys.argv[3],'wb').write(decoded_firmware[:0x2000]+decoded_firmware[0x2000+16:])
print(f'Saved decoded firmware to {sys.argv[3]}')

#save 16 bytes with version string to file
open(sys.argv[4],'wb').write(decoded_firmware[0x2000:0x2000+16])
print(f'Saved version info to {sys.argv[4]}')




elif sys.argv[1]=='pack':
decoded_firmware = open(sys.argv[2],'rb').read()

# visual indicator for firmware size and big warning if too big
current_size = len(decoded_firmware)
max_size = 0xefff

percentage = (current_size / max_size) * 100
bar_length = int(percentage / 2) # Assuming each character represents 2% progress
size_bar = '[' + '=' * bar_length + ' ' * (50 - bar_length) + ']'

print(f"\n\nFirmware takes up {current_size}/{max_size} bytes of available space:")
print(f"Flash usage: {size_bar} {percentage:.2f}%\n\n")

if current_size > max_size:
print("WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
print("WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
print("WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
print("WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n")
print("WARNING: Firmware size exceeds the maximum allowed size of 0xefff (61439) bytes!")
print("Using an oversize firmware will not work correctly and may lead to freezes, crashes and defects.\n")


version_info = open(sys.argv[3],'rb').read()[0:16]

firmware_with_version = decoded_firmware[0:0x2000] + version_info + decoded_firmware[0x2000:]
firmware_with_version_encoded = firmware_xor(firmware_with_version)

open(sys.argv[4],'wb').write(firmware_with_version_encoded+crc16_ccitt_le(firmware_with_version_encoded))
print(f'Saved encoded firmware to {sys.argv[4]}')

23 changes: 23 additions & 0 deletions uvmod_kitchen_v3.00.15/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Create your own custom rom for Quansheng UV-K5!

### Prerequisites
- Windows
- [Latest python](https://www.python.org/downloads/) installed

### How to use this?
- customize included mods, for example `mod_custom_freq_ranges.py` has possibility to edit frequency ranges
- edit `build.bat`/`build.sh`, if you want omit execution of any mod, prefix its line with `::` or `rem` (`#` in `build.sh`)
- [start command prompt](https://www.google.com/search?q=how+to+open+command+prompt+windows) in `uvmod_kitchen_31` directory
- run command `build.bat`/`build.sh`
- look for any errors
- now you can flash new firmware file named `K6_V3.00.15-MODDED.bin`

## List of mods
Porting most useful mods from v2.01.31 to v3.00.15, for now below mods are ported:
- `mod_custom_freq_ranges.py` - customize frequency ranges F1 - F7
- `mod_remove_tx_limits.py` - completely removes transmit limits
- `mod_universal_version.py` - allow to flash output firmware also on `UV-K6` and `UV-5R PLUS`
- `mod_battery_icon.py` - fix original stupid battery icon
- `mod_increases_abr_values.py` - increase the value of the ABR by factor 2, 4 or 8
- `mod_remove_tx_limits.py` - remove TX LImits

0 comments on commit 2f7609b

Please sign in to comment.