# HG changeset patch
# User Jens Jensen <kd4tjx@yahoo.com>
# Date 1384130579 21600
#      Sun Nov 10 18:42:59 2013 -0600
# Node ID ec40bb047d662e84c7956de9ac661a666ae7fca6
# Parent  649e1d06c942a2b4b38ccb3454f403add100db6f
[bj-uv55] initial channel editing support #1201

diff -r 649e1d06c942 -r ec40bb047d66 chirp/uv5r.py
--- a/chirp/uv5r.py	Fri Oct 25 22:50:14 2013 -0500
+++ b/chirp/uv5r.py	Sun Nov 10 18:42:59 2013 -0600
@@ -17,13 +17,18 @@
 import time
 
 from chirp import chirp_common, errors, util, directory, memmap
-from chirp import bitwise
+from chirp import bitwise, os
 from chirp.settings import RadioSetting, RadioSettingGroup, \
     RadioSettingValueInteger, RadioSettingValueList, \
     RadioSettingValueBoolean, RadioSettingValueString, \
     RadioSettingValueFloat, InvalidValueError
 from textwrap import dedent
 
+if os.getenv("CHIRP_DEBUG"):
+    CHIRP_DEBUG = True
+else:
+    CHIRP_DEBUG = False
+
 MEM_FORMAT = """
 #seekto 0x0008;
 struct {
@@ -31,10 +36,13 @@
   lbcd txfreq[4];
   ul16 rxtone;
   ul16 txtone;
-  u8 unused1:4,
+  u8 unused1:3,
+     isuhf:1,
      scode:4;
-  u8 unknown1[1];
-  u8 unknown2:7,
+  u8 unknown1:7,
+     txtoneicon:1;
+  u8 mailicon:3,
+     unknown2:4,
      lowpower:1;
   u8 unknown3:1,
      wide:1,
@@ -187,11 +195,10 @@
 #seekto 0x0F56;
 u16 fm_presets;
 
-#seekto 0x1000;
+#seekto 0x1008;
 struct {
-  u8 unknown1[8];
   char name[7];
-  u8 unknown2;
+  u8 unknown2[9];
 } names[128];
 
 #seekto 0x1818;
@@ -200,7 +207,7 @@
   char line2[7];
 } sixpoweron_msg;
 
-#seekto 0x1828;
+#seekto 0x%04X;
 struct {
   char line1[7];
   char line2[7];
@@ -234,6 +241,13 @@
   struct limit uhf;
 } limits_old;
 
+ #seekto 0x1908;
+struct {
+    struct limit vhf;
+    u8 unk11[11];
+    struct limit uhf;
+} limits_bj55;
+
 """
 
 # 0x1EC0 - 0x2000
@@ -304,6 +318,7 @@
 UV5R_MODEL_291 = "\x50\xBB\xFF\x20\x12\x07\x25"
 UV5R_MODEL_F11 = "\x50\xBB\xFF\x13\xA1\x11\xDD"
 UV82_MODEL =     "\x50\xBB\xFF\x20\x13\x01\x05"
+BJUV55_MODEL   = "\x50\xBB\xDD\x55\x63\x98\x4D"
 
 def _upper_band_from_data(data):
     return data[0x03:0x04]
@@ -311,18 +326,27 @@
 def _upper_band_from_image(radio):
     return _upper_band_from_data(radio.get_mmap())
 
-def _firmware_version_from_data(data):
-    return data[0x1838:0x1848]
+def _firmware_version_from_data(data, version_start = 0x1838, version_stop = 0x1848):
+    version_tag = data[version_start:version_stop]
+    return version_tag
 
 def _firmware_version_from_image(radio):
-    return _firmware_version_from_data(radio.get_mmap())
+    if radio.MODEL == "BJ-UV55":
+        version = _firmware_version_from_data(radio.get_mmap(), 0x1938, 0x193E)
+    else:
+        version = _firmware_version_from_data(radio.get_mmap())
+    if CHIRP_DEBUG:
+        print "firmware version from image: " + util.hexprint(version)
+    return version
 
 def _do_ident(radio, magic):
     serial = radio.pipe
     serial.setTimeout(1)
 
     print "Sending Magic: %s" % util.hexprint(magic)
-    serial.write(magic)
+    for byte in magic:
+        serial.write(byte)
+        time.sleep(0.01)
     ack = serial.read(1)
     
     if ack != "\x06":
@@ -372,10 +396,15 @@
     return chunk
 
 def _get_radio_firmware_version(radio):
-    block1 = _read_block(radio, 0x1EC0, 0x40)
-    block2 = _read_block(radio, 0x1F00, 0x40)
-    block = block1 + block2
-    return block[48:64]
+    if radio.MODEL == "BJ-UV55":
+        block = _read_block(radio, 0x1FF0, 0x40)
+        version = block[0:6]
+    else:    
+        block1 = _read_block(radio, 0x1EC0, 0x40)
+        block2 = _read_block(radio, 0x1F00, 0x40)
+        block = block1 + block2
+        version = block[48:64]
+    return version
 
 def _ident_radio(radio):
     for magic in radio._idents:
@@ -395,14 +424,19 @@
     data = _ident_radio(radio)
 
     # Main block
+    if CHIRP_DEBUG:
+        print "downloading main block..."
     for i in range(0, 0x1800, 0x40):
         data += _read_block(radio, i, 0x40)
         _do_status(radio, i)
-
+    if CHIRP_DEBUG:
+        print "done."
+        print "downloading aux block..."
     # Auxiliary block starts at 0x1ECO (?)
     for i in range(0x1EC0, 0x2000, 0x40):
         data += _read_block(radio, i, 0x40)
-
+    if CHIRP_DEBUG:
+        print "done."
     return memmap.MemoryMap(data)
 
 def _send_block(radio, addr, data):
@@ -427,7 +461,7 @@
     print "Image is %s" % repr(image_version)
     print "Radio is %s" % repr(radio_version)
 
-    if "BFB" not in radio_version and "82" not in radio_version and "USA" not in radio_version:
+    if not any(type in radio_version for type in ["BFB", "82", "USA", "BJ55"]):
         raise errors.RadioError("Unsupported firmware version: `%s'" %
                                 radio_version)
 
@@ -474,6 +508,8 @@
     _idents = [UV5R_MODEL_ORIG,
                UV5R_MODEL_291,
                ]
+    _mem_params = ( 0x1828 # poweron_msg
+                    )
 
     @classmethod
     def get_prompts(cls):
@@ -536,7 +572,7 @@
                 cls._basetype in _firmware_version_from_data(filedata))
 
     def process_mmap(self):
-        self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
+        self._memobj = bitwise.parse(MEM_FORMAT % self._mem_params, self._mmap)
 
     def sync_in(self):
         try:
@@ -691,7 +727,12 @@
             _mem.txfreq = (mem.freq - mem.offset) / 10
         else:
             _mem.txfreq = mem.freq / 10
-
+        
+        if self.MODEL == "BJ-UV55":
+            if (mem.freq - mem.offset) > (400 * 1000000):
+                _mem.isuhf = True
+            else:
+                _mem.isuhf = False
         for i in range(0, 7):
             try:
                 _nam.name[i] = mem.name[i]
@@ -699,12 +740,18 @@
                 _nam.name[i] = "\xFF"
 
         rxmode = txmode = ""
+        if self.MODEL == "BJ-UV55":
+            _mem.txtoneicon = False
         if mem.tmode == "Tone":
             _mem.txtone = int(mem.rtone * 10)
             _mem.rxtone = 0
+            if self.MODEL == "BJ-UV55":
+                _mem.txtoneicon = True
         elif mem.tmode == "TSQL":
             _mem.txtone = int(mem.ctone * 10)
             _mem.rxtone = int(mem.ctone * 10)
+            if self.MODEL == "BJ-UV55":
+                _mem.txtoneicon = True
         elif mem.tmode == "DTCS":
             rxmode = txmode = "DTCS"
             _mem.txtone = UV5R_DTCS.index(mem.dtcs) + 1
@@ -741,16 +788,14 @@
 
     def _is_orig(self):
         version_tag = _firmware_version_from_image(self)
+        if CHIRP_DEBUG:
+            print "@_is_orig, version_tag:", util.hexprint(version_tag)
         try:
             if 'BFB' in version_tag:
                 idx = version_tag.index("BFB") + 3
                 version = int(version_tag[idx:idx+3])
                 return version < 291
-            if 'BF82' in version_tag:
-                return False
-            if 'B82' in version_tag:
-                return False
-            if 'USA' in version_tag:
+            if any(tag in version_tag for tag in ['BF82', 'B82', 'USA', 'BJ55']):
                 return False
         except:
             pass
@@ -771,6 +816,10 @@
         elif 'USA' in version_tag:
             idx = version_tag.index("USA") + 3
             return int(version_tag[idx:idx+3])
+        elif 'BJ55' in version_tag:
+            idx = version_tag.index("BJ55") + 2
+            return int(version_tag[idx:idx+2])
+
         raise Exception("Unrecognized firmware version string")
 
     def _my_upper_band(self):
@@ -963,6 +1012,8 @@
 
         if self._is_orig():
             limit = "limits_old"
+        elif self.MODEL == "BJ-UV55":
+            limit = "limits_bj55"
         else:
             limit = "limits_new"
 
@@ -1299,3 +1350,19 @@
     MODEL = "UV-82"
     _basetype = "82"
     _idents = [UV82_MODEL]
+
+@directory.register
+class BaojieBJUV55Radio(BaofengUV5R):
+    VENDOR = "Baojie"
+    MODEL = "BJ-UV55"
+    _basetype = "BJ55"
+    _idents = [ BJUV55_MODEL ]
+    _mem_params = ( 0x1928  # poweron_msg
+                    )
+    
+    def get_features(self):
+        rf = super(BaojieBJUV55Radio, self).get_features()
+        rf.has_settings = False
+        rf.valid_name_length = 6
+        return rf
+    
