text: # -*- coding: utf-8 -*-
  #############################################################################
  # @package ad_hmi
  # @brief ggg b38 project xcp adapter of python package ad_hmi.
  #############################################################################
  # @author WANG Vincent
  # @copyright (c) All rights reserved.
  #############################################################################
  
  import os
  import json
  
  from lib import Ipc
  from framework import Signal, World, LaneMark, Obstacle, Vehicle
  from IpcTopics import IpcTopic
  
  
  class IpcAdapter:
      def __init__(self, world):
          self.__ipc = Ipc(name=IpcAdapter.__name__)
          self.__world = world
  
      @property
      def ipc(self):
          return self.__ipc
  
      @property
      def world(self):
          return self.__world
  
      def on_msg(self, msg_id, msg_obj):
          raise Exception('Not implemented')
  
      def start(self):
          self.ipc.subscribe_loop()
          print('{: <6}: {} started'.format(os.getpid(), IpcAdapter.__name__))
  
      def stop(self):
          self.ipc.unsubscribe_loop()
          print(IpcAdapter.__name__, 'stopped')
  
      def push(self, dat, key='data'):
          # print('push len=', self.ipc.redis.llen(key))
          return self.ipc.redis.lpush(key, dat)
  
      def pop(self, key='data'):
          # print('pop len=', self.ipc.redis.llen(key))
          return self.ipc.redis.rpop(key)
  
      def expire(self, key, timeout):
          self.ipc.redis.set(key, 1)
          self.ipc.redis.expire(key, timeout)
          # print(self.exists(key))
  
      def exists(self, key):
          return self.ipc.redis.exists(key)
  
  class GggB38IpcAdapter(IpcAdapter):
  
      # enum LongS_States
      (
          Longs_Init,             # 0x0
          Longs_Passive,          # 0x1
          LongS_ActiveControl,    # 0x2, actived
          LongS_ActiveRequest,    # 0x3
          LongS_ActiveSuspend,    # 0x4, actived
          LongS_StandActive,      # 0x5, actived
          LongS_DriverRequest,    # 0x6, actived
          LongS_FadeOut,          # 0x7
          LongS_BrakeOnlyMode,    # 0x8, actived
          LongS_RevFailure,       # 0x9
          LongS_IrrevFailure,     # 0xa
          LongS_INVALID           # 0xb
      ) = range(12)
  
      # enum LatS_States
      (
          LatS_Init,              # 0x0
          LatS_Passvie,           # 0x1
          LatS_ActiveControl,     # 0x2, actived
          LatS_ActiveRequest,     # 0x3
          LatS_ActiveSuspend,     # 0x4
          LatS_Blindness,         # 0x5
          LatS_Failure,           # 0x6
          LatS_INVALID            # 0x7
      ) = range(8)
  
      # LDW
      (
          LdwState_Init,          # 0x0
          LdwState_Off,           # 0x1
          LdwState_Passive,       # 0x2
          LdwState_ActiveRequest, # 0x3
          LdwState_ActiveControl, # 0x4
          LdwState_Failure,       # 0x5
          LdwState_Blocked,       # 0x6
          LdwState_INVALID        # 0x7
      ) = range(8)
  
      # enum Alc_States
      (
          Alc_Init,               # 0x0
          Alc_Passive,            # 0x1
          Alc_ActiveControl,      # 0x2, actived
          Alc_ActiveRequest,      # 0x3
          Alc_TakeOverRequest,    # 0x4, actived
          Alc_RevFailure,         # 0x5
          Alc_IrrevFailure,       # 0x6
          Alc_INVALID             # 0x7
      ) = range(8)
  
      (
          FALSE,
          TRUE
      ) = range(2)
  
      (
          HF_Inactive,
          HF_Active
      ) = range(2)
  
      (
          AD_Inactive,
          AD_Active
      ) = range(2)
  
      def __init__(self, world, main_process=False):
          super().__init__(world)
  
          self.ipc.subs({
                  IpcTopic.GNSS__POS:     self.on_gnss_pos,
                  IpcTopic.XCP__OJB_LANE: self.on_xcp_obj_lane,
          })
  
          self.__main_process = main_process
          # print(os.getpid(), 'main_process=', main_process)
  
          # print(IpcTopic.__dict__)
  
      def on_gnss_pos(self, msg):
          # print('on_gnss_pos', msg)
  
          gnss_pos = json.loads(msg['data'])
          if 1 == gnss_pos['status']:
              self.world.vehicle.lng = gnss_pos['lng']
              self.world.vehicle.lat = gnss_pos['lat']
              self.world.vehicle.alt = gnss_pos['alt']
  
      def on_xcp_obj_lane(self, msg):
          '''
          {
              "objects": [
                  {"class": 1, "state": 1, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 7.798338890075684, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0},
                  {"class": 0, "state": 0, "ax": 0, "vx": 0, "yaw_angle": 0, "collision_prob": 0, "dx": 255.0, "dy": 0.0, "acc": 0, "dodge": 0}
              ],
              "lanes": [
                  {"a5": 0, "a4": 0, "a3": 0.0, "a2": 0.0, "a1": 0.0, "a0": 0.0, "type": 0, "end": 100.0, "start": -50.0},
                  {"a5": 0, "a4": 0, "a3": 0.0, "a2": 0.0, "a1": 0.0, "a0": 0.0, "type": 0, "end": 100.0, "start": -50.0},
                  {"a5": 0, "a4": 0, "a3": 0.0, "a2": 0.0, "a1": 0.0, "a0": 0.0, "type": 0, "end": 100.0, "start": -50.0},
                  {"a5": 0, "a4": 0, "a3": 0.0, "a2": 0.0, "a1": 0.0, "a0": 0.0, "type": 0, "end": 100.0, "start": -50.0}
              ],
              "vehInfo": {
                  "VehSpd": 0,            # vehicle speed
                  "axv": 0.0,             # vehicle longitudinal acceleration
                  "ayv": 0.0,             # vehicle latitudinal acceleration
                  "ACC": 1,               # ACC state
                  "TJA": 1,               # TJA state
                  "ALC": 1,               # ALC state
                  "HF": 0,                        # HF state, [0, 1]
                  "LOC_L": 1,
                  "LOC_R": 0,
                  "LDW": 2,                       # LDW state
                  "Gear": 4,                      # gear state
                  "TargetSpd": 255.5,             # target speed
                  "TurnLight_L": 0,               # left turn light
                  "TurnLight_R": 0,               # right turn light
                  "LC_fail_reason": 0,            # lane change failed reason
                  "LC_progress": 0,               # lane change progress, [0-100]
                  "LC_reason": 0,                 # ???
                  "LC_confirmation": 0            # true/false
                  "Hands_on_warning_level": 0,    # hands on warning level, {0x0: no warning, 0x1: attention warning, 0x2: urgent warning}
                  "HF_tor_reason": 0,             # hf takeover request, {0x0:no warning, 0x1: takeover request, 0x2: safestop}
                  "HF_exit_forecast": 0,          #
                  "Eyes_on_warning_level": 0,     # eyes on warning, {0x0: no warning, 0x1: attention warning, 0x2: urgent warning}
                  "HF_available": 0,              # hf available, {true, false}
                  "HF_quit": 0,                   # hf quit, {true, false}
                  "AD": 0,                        # ad state
                  "AD_enter_ramp": 0,
                  "AD_inactive_reason": 0,       #
                  "is_AD_active_reminder": 0     #
              },
              "traj": {                       # trajectory of ego vehicle
                  "a5": 0.0,                  # coefficent c5
                  "a4": 0.0,                  # coefficent c4
                  "a3": 0.0,                  # coefficent c3
                  "a2": 0.0,                  # coefficent c2
                  "a1": 0.0,                  # coefficent c1
                  "a0": 0.0,                  # coefficent c0
                  "dx_end": 0.0,              # end point of dx
                  # safe area display condition:
                  # (TJA active && ALC not active) && (left lane mark available && right lane mark available) && (vehicle speed > 50kph)
                  "ss_status": 0,             # safe area status, [0, 1]
                  "ss_left_start": -200.0,    # left safe area start in dx
                  "ss_left_end": 34.421875,   # left safe area end in dx
                  "ss_right_start": -200.0,   # right safe area start in dx
                  "ss_right_end": 200.0       # right safe area end in dx
              }
          }
          '''
          # print('on_xcp_obj_lane', msg)
  
          objs_lanes = json.loads(msg['data'])
  
          ################################################################################################################
          # vehInfo
          ################################################################################################################
          # self.redis_dict['vehInfo'].update({'VehSpd': 0, 'axv': 0, 'ayv': 0, 'ACC': 0, 'TJA': 0,
          #  'ALC': 0, 'HF': 0, 'LOC_L': 0, 'LOC_R': 0, 'LDW': 0,
          #  'Gear': 0, 'TargetSpd': 0, 'TurnLight_L': 0, 'TurnLight_R': 0})
          self.world.vehicle.brake.update(objs_lanes['vehInfo']['brake'] != 0) # adapte signal
          self.world.vehicle.update_velocity(objs_lanes['vehInfo']['VehSpd'])
          self.world.vehicle.axv.update(objs_lanes['vehInfo']['axv'])
          self.world.vehicle.ayv.update(objs_lanes['vehInfo']['ayv'])
          self.world.vehicle._turn_left = objs_lanes['vehInfo']['TurnLight_L']
          self.world.vehicle._turn_right = objs_lanes['vehInfo']['TurnLight_R']
          self.world.vehicle._gear_state = objs_lanes['vehInfo']['Gear']
  
          #---------------------------------------------------------------------------------------------------------------
          # objs_lanes['vehInfo']['LOC_L']
          # objs_lanes['vehInfo']['LOC_R']
  
          #---------------------------------------------------------------------------------------------------------------
          # acc target speed
          self.world.vehicle._acc_target_speed = objs_lanes['vehInfo']['TargetSpd']
          self.world.vehicle.adas.safe_dist.update(objs_lanes['vehInfo']['dDesire']) # FIXME:
          # function state
          self.world.vehicle.adas.lng_active.update(GggB38IpcAdapter.is_long_actived(objs_lanes['vehInfo']['ACC']))
          self.world.vehicle.adas.lat_active.update(GggB38IpcAdapter.is_lat_actived(objs_lanes['vehInfo']['TJA']))
          self.world.vehicle.adas.ldw_active.update(GggB38IpcAdapter.is_ldw_actived(objs_lanes['vehInfo']['LDW']))
          self.world.vehicle.adas.alc_active.update(GggB38IpcAdapter.is_alc_actived(objs_lanes['vehInfo']['ALC']))
  
          #---------------------------------------------------------------------------------------------------------------
          # warning info
          # LC
          ret = self.world.vehicle.adas.lc_reason.update(objs_lanes['vehInfo']['LC_reason'])
          if Signal.IS_CHANGED(ret):
              if objs_lanes['vehInfo']['Auto_LC_Sts'] == 1:
                  if self.world.vehicle.adas.lc_reason.val == 1:
                      self.audio_notify('lc_reason_1')
                  elif self.world.vehicle.adas.lc_reason.val == 2:
                      self.audio_notify('lc_reason_2')
                  elif self.world.vehicle.adas.lc_reason.val == 3:
                      self.audio_notify('lc_reason_3')
                  elif self.world.vehicle.adas.lc_reason.val == 5:
                      self.audio_notify('lc_reason_5')
                  elif self.world.vehicle.adas.lc_reason.val == 8:
                      self.audio_notify('lc_reason_8')
                  elif self.world.vehicle.adas.lc_reason.val == 9:
                      self.audio_notify('lc_reason_9')
                  elif self.world.vehicle.adas.lc_reason.val == 10:
                      self.audio_notify('lc_reason_10')
                  elif self.world.vehicle.adas.lc_reason.val == 11:
                      self.audio_notify('lc_reason_11')
                  elif self.world.vehicle.adas.lc_reason.val == 12:
                      self.audio_notify('lc_reason_12')
                  elif self.world.vehicle.adas.lc_reason.val == 13:
                      self.audio_notify('lc_reason_13')
                  elif self.world.vehicle.adas.lc_reason.val == 14:
                      self.audio_notify('lc_reason_14')
                  elif self.world.vehicle.adas.lc_reason.val == 15:
                      self.audio_notify('lc_reason_15')
                  elif self.world.vehicle.adas.lc_reason.val == 17:
                      self.audio_notify('lc_reason_17')
          self.world.vehicle.adas.lc_progress.update(objs_lanes['vehInfo']['LC_progress'])
          ret = self.world.vehicle.adas.lc_fail_reason.update(objs_lanes['vehInfo']['LC_fail_reason'])
          if Signal.IS_CHANGED(ret):
              if self.world.vehicle.adas.lc_fail_reason.val == 0x1:
                  self.audio_notify('lc_fail_1')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0x2:
                  self.audio_notify('lc_fail_2')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0x3:
                  self.audio_notify('lc_fail_3')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0x4:
                  if objs_lanes['vehInfo']['Auto_LC'] == 1:
                      self.audio_notify('lc_fail_4_l')
                  elif objs_lanes['vehInfo']['Auto_LC'] == 2:
                      self.audio_notify('lc_fail_4_r')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0x5:
                  self.audio_notify('lc_fail_5')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0x6:
                  self.audio_notify('lc_fail_6')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0x7:
                  self.audio_notify('lc_fail_7')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0x8:
                  self.audio_notify('lc_fail_8')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0x9:
                  self.audio_notify('lc_fail_9')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0xa:
                  self.audio_notify('lc_fail_10')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0xb:
                  self.audio_notify('lc_fail_11')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0xc:
                  self.audio_notify('lc_fail_12')
              elif self.world.vehicle.adas.lc_fail_reason.val == 0xd:
                  self.audio_notify('lc_fail_13')
          if self.world.vehicle.adas.lc_confirmation.update(objs_lanes['vehInfo']['LC_confirmation']) == Signal.RISING:
              self.audio_notify('popup')
          ret = self.world.vehicle.adas.lc_trigger_side.update(objs_lanes['vehInfo']['Auto_LC'])  # direction: none/left/right
          if Signal.IS_CHANGED(ret):
              if objs_lanes['vehInfo']['Auto_LC_Sts'] == 0 and objs_lanes['vehInfo']['AD'] == 1:
                  if objs_lanes['vehInfo']['LC_reason'] in (
                      # 0, # None = 0
                      1, # left_is_fast = 1
                      2, # right_is_faster = 2
                      3, # right_fast = 3
                      # 4, # overtaken_by_egoRight = 4
                      5, # overtaken_by_right = 5
                      # 6, # reset = 6
                      # 7, # objects_others = 7
                      8, # Map_Front_lane_die = 8
                      9, # Map_Highspeed_inter_ramp_ahead = 9
                      10, # Map_Enter_Highspeed_inter_ramp = 10
                      11, # Map_Highspeed_inter_exit_ramp_ahead = 11
                      12, # Map_Exit_Highspeed_inter_ramp = 12
                      13, # Map_Divide_road = 13
                      14, # Map_Control_lane = 14
                      15, # Map_Traffic_Congestion = 15
                      # 16, # Map_Others = 16
                      17, # avoid_ramp_in_most_right = 17
                  ):
                      if objs_lanes['vehInfo']['Auto_LC'] == 1:
                          self.audio_notify('lc_recommand_l')
                      elif objs_lanes['vehInfo']['Auto_LC'] == 2:
                          self.audio_notify('lc_recommand_r')
          ret = self.world.vehicle.adas.lc_is_sys_hdl.update(objs_lanes['vehInfo']['Auto_LC_Sts'])
  
          #---------------------------------------------------------------------------------------------------------------
          # HF
          ret = self.world.vehicle.adas.hf_active.update(GggB38IpcAdapter.is_hf_actived(objs_lanes['vehInfo']['HF']))
          if ret == Signal.RISING:
              self.audio_notify('ad_act')
          self.world.vehicle.adas.hf_available.update(GggB38IpcAdapter.is_hf_available(objs_lanes['vehInfo']['HF_available']))
          ret = self.world.vehicle.adas.hands_on_warning_level.update(objs_lanes['vehInfo']['Hands_on_warning_level'])
          if Signal.IS_CHANGED(ret):
              if self.world.vehicle.adas.hands_on_warning_level.val == 1:
                  self.audio_notify('hands_on_1')
              elif self.world.vehicle.adas.hands_on_warning_level.val == 2:
                  self.audio_notify('hands_on_2')
          ret = self.world.vehicle.adas.hf_tor_warning_level.update(objs_lanes['vehInfo']['HF_tor_reason'])
          if Signal.IS_CHANGED(ret):
              if self.world.vehicle.adas.hf_tor_warning_level.val == 1:
                  self.audio_notify('hf_tor_1')
              elif self.world.vehicle.adas.hf_tor_warning_level.val == 2:
                  self.audio_notify('hf_tor_2')
          # self.world.vehicle.adas.hf_exit_forecast.update(objs_lanes['vehInfo']['HF_exit_forecast']) # nouse
          ret = self.world.vehicle.adas.hf_eyes_on_warning_level.update(objs_lanes['vehInfo']['Eyes_on_warning_level'])
          if Signal.IS_CHANGED(ret):
              if self.world.vehicle.adas.hf_eyes_on_warning_level.val == 1:
                  self.audio_notify('eyes_on_1')
              elif self.world.vehicle.adas.hf_eyes_on_warning_level.val == 2:
                  self.audio_notify('eyes_on_2')
          if self.world.vehicle.adas.hf_quit.update(objs_lanes['vehInfo']['HF_quit'] == 1) == Signal.RISING:
              self.audio_notify('ad_quit')
  
          #---------------------------------------------------------------------------------------------------------------
          # ad
          self.world.vehicle.adas.ad_active.update(objs_lanes['vehInfo']['AD'])
          ret = self.world.vehicle.adas.ad_enter_ramp.update(objs_lanes['vehInfo']['AD_enter_ramp'])
          if Signal.IS_CHANGED(ret):
              if self.world.vehicle.adas.ad_enter_ramp.val == 1:
                  self.audio_notify('ad_enter_ramp')
          self.world.vehicle.adas.ad_inactive_reason.update(objs_lanes['vehInfo']['AD_inactive_reason'])
          ret = self.world.vehicle.adas.ad_available_reminder.update(objs_lanes['vehInfo']['AD_available'])
          if Signal.IS_CHANGED(ret):
              if self.world.vehicle.adas.ad_available_reminder.val == 1:
                  self.audio_notify('ad_available_1')
              elif self.world.vehicle.adas.ad_available_reminder.val == 2:
                  self.audio_notify('ad_available_2')
              elif self.world.vehicle.adas.ad_available_reminder.val == 3:
                  self.audio_notify('ad_available_3')
          ret = self.world.vehicle.adas.ad_active_reminder.update(objs_lanes['vehInfo']['is_AD_active_reminder'] == 1)
          if ret == Signal.RISING:
              self.audio_notify('ad_act')
          ret = self.world.vehicle.adas.ad_quit.update(objs_lanes['vehInfo']['AD_quit'] == 1)
          if ret == Signal.RISING:
              self.audio_notify('ad_quit')
          self.world.vehicle.adas.ad_switch.update(objs_lanes['vehInfo']['AD_Switch'])
          ret = self.world.vehicle.adas.ad_switch_on_reminder.update(objs_lanes['vehInfo']['AD_on_remind'])
          if Signal.IS_CHANGED(ret) and self.world.vehicle.adas.ad_switch_on_reminder.val == 1:
              self.audio_notify('ad_available_4')
  
          ################################################################################################################
          # reset dodge state
          self.world.vehicle.adas.dodge_reset()
  
          #---------------------------------------------------------------------------------------------------------------
          # objects
          for i, obj in enumerate(objs_lanes['objects']):
              self.world.obstacles[str(i)].update_class(GggB38IpcAdapter.convert_obstacle_class(obj['class']))
              self.world.obstacles[str(i)].update_state(GggB38IpcAdapter.convert_obstacle_state(obj['state']))
  
              self.world.obstacles[str(i)]._collision_prob = obj['collision_prob']
              self.world.obstacles[str(i)]._acc = obj['acc']
              self.world.obstacles[str(i)]._dodge = obj['dodge']
  
              self.world.obstacles[str(i)]._fused = i <= 32 #
  
              self.world.obstacles[str(i)].x = round(float(obj['dx']), 2)
              self.world.obstacles[str(i)].y = round(float(obj['dy']), 1)
  
              self.world.obstacles[str(i)].yaw = obj['yaw_angle']
  
              self.world.obstacles[str(i)]._ax = obj['ax']
              self.world.obstacles[str(i)]._vx = obj['vx']
              self.world.obstacles[str(i)]._index = obj['index']
  
              # update dodge state
              if self.world.obstacles[str(i)].is_dodge_left():
                  self.world.vehicle.adas.dodge_left.val = True
              if self.world.obstacles[str(i)].is_dodge_right():
                  self.world.vehicle.adas.dodge_right.val = True
  
          for i in range(len(objs_lanes['objects']), len(self.world.obstacles.keys())):
              self.world.obstacles[str(i)].update_state(Obstacle.ST_INVALID)
  
          # lanes
          for i, lane in enumerate(objs_lanes['lanes']):
              self.world.road._lane_marks[i]._type = GggB38IpcAdapter.convert_lane_type(lane['type'])
              self.world.road._lane_marks[i]._raw_type = GggB38IpcAdapter.convert_lane_type(lane['type'])
              self.world.road._lane_marks[i]._state = GggB38IpcAdapter.convert_lane_state(lane['type'])
  
              self.world.road._lane_marks[i].c0 = float(lane['a0'])
              self.world.road._lane_marks[i].c1 = float(lane['a1'])
              self.world.road._lane_marks[i].c2 = float(lane['a2'])/2
              self.world.road._lane_marks[i].c3 = float(lane['a3'])/6
              self.world.road._lane_marks[i].c4 = 0 #round(float(lane['a4'])/24, 8)
              self.world.road._lane_marks[i].c5 = 0 #round(float(lane['a5'])/120, 8)
  
              self.world.road._lane_marks[i].dx_end = lane['end']
              self.world.road._lane_marks[i].dx_start = lane['start']
              self.world.road._lane_marks[i]._idx = i
  
          # lat actived lane mark
          self.world.road.high_light_ego_lane(self.world.vehicle.adas.is_lat_act())
          # ldw warning lane mark
          self.world.road.update_ldw_wrn(self.world.vehicle.adas.is_ldw_act())
          # update ego lane painting
          self.world.road.update_ego_lane()
  
          ##############################
          self.fake_trajectory(self.world.vehicle, self.world.road)
  
          # traj
          if 'traj' in objs_lanes:
              # print(objs_lanes['traj'])
              # print(type(objs_lanes['traj']['a5']))
              # print(float(objs_lanes['traj']['a5']))
              if self.world.vehicle.adas.is_alc_act():
                  self.world.vehicle._trajectory.c5 = float(objs_lanes['traj']['a5'])/120
                  self.world.vehicle._trajectory.c4 = float(objs_lanes['traj']['a4'])/24
                  self.world.vehicle._trajectory.c3 = float(objs_lanes['traj']['a3'])/6
                  self.world.vehicle._trajectory.c2 = float(objs_lanes['traj']['a2'])/2
                  self.world.vehicle._trajectory.c1 = float(objs_lanes['traj']['a1'])
                  self.world.vehicle._trajectory.c0 = float(objs_lanes['traj']['a0'])
                  self.world.vehicle._trajectory.dx_start = 2
                  self.world.vehicle._trajectory.dx_end = float(objs_lanes['traj']['dx_end'])
                  self.world.vehicle._trajectory._is_fake = False
  
              self.world.vehicle._egoLaneChangeGo = (objs_lanes['traj']['ss_status'] == 1)
              self.world.safe_area.update_left(objs_lanes['traj']['ss_left_start'], objs_lanes['traj']['ss_left_end'])
              self.world.safe_area.update_right(objs_lanes['traj']['ss_right_start'], objs_lanes['traj']['ss_right_end'])
  
      def fake_trajectory(self, vehicle, road):
          if (vehicle.adas.is_lng_act() or
             vehicle.adas.is_lat_act() or
             vehicle.adas.is_alc_act() or
             vehicle.adas.is_ldw_act() or
             vehicle.adas.is_hf_act()) and \
             (not vehicle.adas.is_ad_act()):
  
              if road._lane_marks[0]._state == LaneMark.ST_AVAILABLE and road._lane_marks[1]._state == LaneMark.ST_AVAILABLE:
                  vehicle._trajectory.coeff_copy(road._lane_marks[0])
                  vehicle._trajectory.c0 = 0 #(road._lane_marks[0].c0 + road._lane_marks[1].c0) / 2
                  vehicle._trajectory.dx_start = 2
                  vehicle._trajectory.dx_end = road._lane_marks[0].dx_end
                  vehicle._trajectory._is_fake = True
              else:
                  vehicle._trajectory.reset()
          else:
              vehicle._trajectory.reset()
  
  
      @staticmethod
      def convert_lane_type(type):
          '''
          #define ENI_LANE_SEGMENT_BORDER_VIRTUAL.static_cast<vfc::uint8_t>(0)
          #define ENI_LANE_SEGMENT_BORDER_UNKNOWN.static_cast<vfc::uint8_t>(1)
          #define ENI_LANE_SEGMENT_BORDER_DASHED_LINE_NORMAL.static_cast<vfc::uint8_t>(2)
          #define ENI_LANE_SEGMENT_BORDER_SOLID_LINE_NORMAL.static_cast<vfc::uint8_t>(3)
          #define ENI_LANE_SEGMENT_BORDER_DASHED_LINE_EXCEPT.static_cast<vfc::uint8_t>(4)
          #define ENI_LANE_SEGMENT_BORDER_SOLID_LINE_EXCEPT.static_cast<vfc::uint8_t>(5)
          #define ENI_LANE_SEGMENT_BORDER_ROAD_EDGE.static_cast<vfc::uint8_t>(6)
          #define ENI_LANE_SEGMENT_BORDER_CONSTRUCTION_ELEMENT.static_cast<vfc::uint8_t>(7)
          '''
          if type == 0:
              return LaneMark.DASHED
          elif type == 1:
              return LaneMark.INVALID
          elif type == 2:
              return LaneMark.DASHED
          elif type == 3:
              return LaneMark.SOLID
          elif type == 4:
              return LaneMark.DASHED
          elif type == 5:
              return LaneMark.SOLID
          elif type == 6:
              return LaneMark.ROAD_EDGE
          elif type == 7:
              return LaneMark.BARRIER
          else:
              return LaneMark.INVALID
  
      @staticmethod
      def convert_lane_state(type):
          # 0 means does not display
          # define ENI_LANE_SEGMENT_BORDER_VIRTUAL static_cast<vfc::uint8_t>(0)
          # define ENI_LANE_SEGMENT_BORDER_UNKNOWN static_cast<vfc::uint8_t>(1)
          # define ENI_LANE_SEGMENT_BORDER_DASHED_LINE_NORMAL static_cast<vfc::uint8_t>(2)
          # define ENI_LANE_SEGMENT_BORDER_SOLID_LINE_NORMAL static_cast<vfc::uint8_t>(3)
          # define ENI_LANE_SEGMENT_BORDER_DASHED_LINE_EXCEPT static_cast<vfc::uint8_t>(4)
          # define ENI_LANE_SEGMENT_BORDER_SOLID_LINE_EXCEPT static_cast<vfc::uint8_t>(5)
          # define ENI_LANE_SEGMENT_BORDER_ROAD_EDGE static_cast<vfc::uint8_t>(6)
          # define ENI_LANE_SEGMENT_BORDER_CONSTRUCTION_ELEMENT static_cast<vfc::uint8_t>(7)
          if type == 0:
              return LaneMark.ST_INVALID
          else:
              return LaneMark.ST_AVAILABLE
  
      @staticmethod
      def convert_obstacle_class(clazz):
          '''
             UNKNOWN       = 0U,
              PASSENGER_CAR = 1U,
              TWO_WHEELER   = 2U,
              TRUCK         = 3U,
              PASSENGER     = 4U
          '''
          if clazz == 0:
              return Obstacle.CLS_OTH
          elif clazz == 1:
              return Obstacle.CLS_CAR
          elif clazz == 2:
              return Obstacle.CLS_MOT
          elif clazz == 3:
              return Obstacle.CLS_TRK
          elif clazz == 4:
              return Obstacle.CLS_PED
  
      @staticmethod
      def convert_obstacle_state(state):
          if state == 0: # not dectected
              return Obstacle.ST_INVALID
          else: # otherwise
              return Obstacle.ST_AVAILABLE
  
      @staticmethod
      def is_long_actived(long_state):
          '''
          return True or False
          '''
          return long_state in (GggB38IpcAdapter.LongS_ActiveControl,
                                GggB38IpcAdapter.LongS_ActiveSuspend,
                                GggB38IpcAdapter.LongS_StandActive,
                                GggB38IpcAdapter.LongS_DriverRequest,
                                GggB38IpcAdapter.LongS_BrakeOnlyMode)
  
      @staticmethod
      def is_lat_actived(lat_state):
          '''
          return True or False
          '''
          return lat_state in (GggB38IpcAdapter.LatS_ActiveControl,)
  
      @staticmethod
      def is_alc_actived(alc_state):
          '''
          return True or False
          '''
          return alc_state in (GggB38IpcAdapter.Alc_ActiveControl,
                               GggB38IpcAdapter.Alc_TakeOverRequest)
  
      @staticmethod
      def is_ldw_actived(ldw_state):
          '''
          return True or False
          '''
          return ldw_state in (GggB38IpcAdapter.LdwState_ActiveControl,)
  
      @staticmethod
      def is_hf_actived(hf_state):
          '''
          return True or False
          '''
          return hf_state == GggB38IpcAdapter.HF_Active
  
      @staticmethod
      def is_hf_available(hf_available):
          '''
          return True or False
          '''
          return hf_available == GggB38IpcAdapter.TRUE
  
      @staticmethod
      def is_ad_actived(ad_active):
          return ad_active == GggB38IpcAdapter.AD_Active
  
      ####################################################################################################################
      AUDIO_MAP = {
          # tone ###############################################################
          'ad_act':          'ADactivation',
          'ad_quit':         'ADquit',
          'popup':            'popup',
          # voice prompt ########################################################
          'ad_available_1':  'presstoactivateNOH',            # 导航领航功能可用，按下主开关激活
          'ad_available_2':  'presstoactivateNOH',            # 导航领航功能可用，按下主开关激活
          'ad_available_3':  'activateNOHrefermap',           # 导航领航功能可用，参照图示两步激活
          'ad_available_4':  'presstoactivateNOH',            # 导航领航功能可用，按下主开关激活
          'hf_tor_1':         'pleasetakeover',               # 请接管车辆
          'hf_tor_2':         'hf_tor_2',                     # 正在安全刹停，请接管车辆
          'hands_on_1':       'pleaseholdsteer',              # 请保持手握方向盘
          'hands_on_2':       'pleaseholdsteer',              # 请保持手握方向盘
          'eyes_on_1':        'eyes_on_1',                    # 请保持专心驾驶
          'eyes_on_2':        'eyes_on_1',                    # 请保持专心驾驶
          'ad_enter_ramp':   '2miletoramp',                   # 前方2KM进入出口匝道
          'lc_fail_1':        'solidlinenochange',            # 实线是不能变道的呦
          'lc_fail_2':        'lanenotclearnoautochange',     # 车道线不清晰，就先不自动变道啦
          'lc_fail_3':        'sharpcurvenochange',           # 弯太急了，过了这个弯再自动变道吧
          'lc_fail_4_l':      'toomanycarstochangeleft',      # 左侧车道车太多啦，就先不自动变道啦
          'lc_fail_4_r':      'lc_fail_4_r',                  # 右侧车道车太多啦，就先不自动变道啦
          'lc_fail_5':        'lc_fail_5',                    # 车速在60-120KPH之间，高架高速上才可以自动变道哟
          'lc_fail_6':        'lc_fail_6',                    # 方向盘交给你了，就不自动变道啦
          'lc_fail_7':        'lc_fail_7',                    # 转向灯关掉了，就不自动变道啦
          'lc_fail_8':        'lc_fail_8',                    # 双闪打开了，就不自动变道啦
          'lc_fail_9':        'lc_fail_9',                    # 主动变道功能关闭状态下，是不能自主变道的哟
          'lc_fail_10':       'sharpcurvequit',               # 没等到自动变道机会，你帮我变过去吧
          'lc_fail_11':       'lc_fail_11',                   # 智能巡航系统关闭状态下，是不能变道的哟
          'lc_fail_12':       'lc_fail_12',                   # 主动变道系统错误，变道失败
          'lc_fail_13':       'lc_fail_13',                   # 旁边车道有点危险，就先不自动变道啦
          'lc_reason_1':      'lc_reason_1',                  # 向左变道进入快车道
          'lc_reason_2':      'lc_reason_2',                  # 右边比较快，变道进入右车道
          'lc_reason_3':      'lc_reason_3',                  # 右边比较快，变道进入右车道
          'lc_reason_5':      'lc_reason_5',                  # 右边比较快，变道进入右车道
          'lc_reason_8':      'lc_reason_8',                  # 前方车道消失，系统自动变道
          'lc_reason_9':      'lc_reason_9',                  # 自动变道，准备进入匝道
          'lc_reason_10':     'lc_reason_10',                 # 自动变道，进入匝道
          'lc_reason_11':     'lc_reason_11',                 # 变道进入匝道左侧车道
          'lc_reason_12':     'lc_reason_12',                 # 自动变道，准备汇入主路
          'lc_reason_13':     'lc_reason_13',                 # 前方道路分叉，系统自动变道
          'lc_reason_14':     'lc_reason_14',                 # 前方道路管制，系统自动变道
          'lc_reason_15':     'lc_reason_15',                 # 前方红绿灯，系统自动变道
          'lc_reason_17':     'lc_reason_17',                 # 前方右侧汇入车辆，系统自动变道
          'lc_recommand_l':   'lc_recommand_l',               # 推荐向左变道
          'lc_recommand_r':   'lc_recommand_r',               # 推荐向右变道
      }
      def audio_notify(self, type):
          if self.__main_process:
              print('{: <6}: {}'.format(os.getpid(), type))
  
              if type in GggB38IpcAdapter.AUDIO_MAP.keys():
                  self.ipc.publish(IpcTopic.AUD__AUDIO, GggB38IpcAdapter.AUDIO_MAP[type])
              else:
                  print('Unknown audio notification: {}'.format(type))
  