From 4d44ed185203088052b10a8d1e3526fcbbc88331 Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期日, 15 九月 2019 18:42:31 +0800
Subject: [PATCH] obd 数据解码逻辑完成

---
 src/test/kotlin/com/flightfeather/obd/Test.kt                                        |   88 ++++
 src/main/kotlin/com/flightfeather/obd/lightshare/bean/ObdDataVo.kt                   |    2 
 src/main/kotlin/com/flightfeather/obd/common/utils/FileUtil.kt                       |  103 ++++
 src/main/kotlin/com/flightfeather/obd/socket/decoder/RealTimeDataDecoder.kt          |   26 +
 src/main/kotlin/com/flightfeather/obd/socket/eunm/ObdCommandUnit.kt                  |   14 
 pom.xml                                                                              |   13 
 src/main/kotlin/com/flightfeather/obd/repository/impl/ObdDataDaoImpl.kt              |   77 +++
 src/main/kotlin/com/flightfeather/obd/socket/bean/EngineDataFlow.kt                  |   33 +
 src/main/kotlin/com/flightfeather/obd/common/packgeinfo                              |    0 
 src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/DataUnitDecoderImpl.kt     |  123 +++++
 src/main/kotlin/com/flightfeather/obd/socket/bean/CarLogOutData.kt                   |   14 
 src/main/kotlin/com/flightfeather/obd/socket/eunm/ObdDataType.kt                     |   19 
 src/main/kotlin/com/flightfeather/obd/socket/bean/ObdPackageData.kt                  |   16 
 src/main/kotlin/com/flightfeather/obd/socket/decoder/DataPackageDecoder.kt           |   42 ++
 src/main/kotlin/com/flightfeather/obd/socket/bean/TimeCalibrationData.kt             |    8 
 src/main/kotlin/com/flightfeather/obd/socket/SocketServerClient.kt                   |   14 
 src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/DataPackageDecoderImpl.kt  |   98 ++++
 src/main/kotlin/com/flightfeather/obd/socket/bean/DataUnit.kt                        |    8 
 src/main/kotlin/com/flightfeather/obd/socket/bean/SupplementDataFlow.kt              |   57 ++
 src/main/kotlin/com/flightfeather/obd/repository/ObdDataRepository.kt                |    4 
 src/main/kotlin/com/flightfeather/obd/socket/bean/ReplacementData.kt                 |    9 
 src/main/resources/log4j2.xml                                                        |   67 +++
 src/main/kotlin/com/flightfeather/obd/socket/decoder/VehicleDataDecoder.kt           |   35 +
 src/main/kotlin/com/flightfeather/obd/socket/decoder/DataUnitDecoder.kt              |   36 +
 src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/RealTimeDataDecoderImpl.kt |  163 +++++++
 src/main/kotlin/com/flightfeather/obd/socket/bean/RealTimeData.kt                    |   13 
 src/main/kotlin/com/flightfeather/obd/socket/bean/CarRegisterData.kt                 |   20 
 src/test/kotlin/com/flightfeather/obd/ObdApplicationTests.kt                         |   11 
 src/main/kotlin/com/flightfeather/obd/socket/MessageManager.kt                       |   43 +
 src/main/kotlin/com/flightfeather/obd/socket/bean/ObdData.kt                         |   25 +
 src/main/kotlin/com/flightfeather/obd/socket/ServerHandler.kt                        |   33 +
 src/main/resources/application.yml                                                   |    1 
 32 files changed, 1,188 insertions(+), 27 deletions(-)

diff --git a/pom.xml b/pom.xml
index ed3e0cc..5ee699e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,6 +27,13 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <!-- 鍘婚櫎鏃og渚濊禆 -->
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.module</groupId>
@@ -103,6 +110,12 @@
             <version>1.2.12</version>
         </dependency>
 
+        <!--澧炲姞log4j2渚濊禆鈫�-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+        </dependency>
+
     </dependencies>
 
     <build>
diff --git a/src/main/kotlin/com/flightfeather/obd/common/packgeinfo b/src/main/kotlin/com/flightfeather/obd/common/packgeinfo
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/common/packgeinfo
diff --git a/src/main/kotlin/com/flightfeather/obd/common/utils/FileUtil.kt b/src/main/kotlin/com/flightfeather/obd/common/utils/FileUtil.kt
new file mode 100644
index 0000000..7dea200
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/common/utils/FileUtil.kt
@@ -0,0 +1,103 @@
+package com.flightfeather.obd.common.utils
+
+import java.io.BufferedWriter
+import java.io.File
+import java.io.FileWriter
+import java.text.SimpleDateFormat
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/11
+ */
+class FileUtil {
+
+    private var file: File
+    private var basePath:String = "${File.separator}ObdData${File.separator}"
+    private var closeThread: Thread? = null
+    private var fw: FileWriter? = null
+    private var bw: BufferedWriter? = null
+
+    init {
+        val fileName = "data-${SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Date())}.txt"
+        val path = "$basePath$fileName"
+        file = File(path)
+    }
+
+    companion object{
+        var instance: FileUtil? = null
+        get() {
+            if (field == null) {
+                field = FileUtil()
+            }
+            return field
+        }
+    }
+
+    fun saveObdData(str: String) {
+        //妫�鏌ユ枃妗f槸鍚﹀瓨鍦�
+        if (!file.exists()) {
+            file.parentFile.mkdirs()
+            println("----鍒涘缓鏂囦欢澶癸細${file.parentFile.absolutePath}")
+            file.createNewFile()
+            println("----鍒涘缓鏂囦欢锛�${file.absolutePath}")
+        }
+        //鏂囦欢鏈�澶�512Kb,瓒呰繃鍚庢柊寤烘枃妗�
+        if (file.length() + str.toByteArray().size > 512 * 1024) {
+            val fileName = "data-${SimpleDateFormat("yyyy-MM-dd-hh-mm-ss").format(Date())}.txt"
+            val path = "$basePath$fileName"
+            file = File(path)
+            file.createNewFile()
+
+            //鍏抽棴鍘熸湁杈撳嚭娴�
+            bw?.run {
+                flush()
+                close()
+            }
+            fw?.run {
+                flush()
+                close()
+            }
+            //鏂板缓杈撳嚭娴�
+            fw = FileWriter(file, true)
+            bw = BufferedWriter(fw)
+        }
+        //绗竴娆″啓鏂囨。鏃跺垵濮嬪寲杈撳嚭娴�
+        if (bw == null || fw == null) {
+            fw = FileWriter(file, true)
+            bw = BufferedWriter(fw)
+        }
+
+        bw?.run {
+            write(str)
+            newLine()
+            flush()
+        }
+
+        readyToShutDownStream(bw, fw)
+        println("----鍐欏叆瀹屾垚")
+
+    }
+
+    private fun readyToShutDownStream(bw: BufferedWriter?, fw:FileWriter?) {
+        //缁堢涓婁竴娆$殑璁℃椂绾跨▼
+        closeThread?.interrupt()
+        closeThread = Thread(Runnable {
+            //2鍒嗛挓娌℃湁鏂扮殑鏁版嵁鍐欏叆灏卞叧闂緭鍑烘祦
+            try {
+                Thread.sleep(20 * 1000)
+            } catch (e: Throwable) {
+            }
+            bw?.run {
+                close()
+            }
+            this.bw = null
+            fw?.run {
+                close()
+            }
+            this.fw = null
+        }).also {
+            it.start()
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/lightshare/bean/ObdDataVo.kt b/src/main/kotlin/com/flightfeather/obd/lightshare/bean/ObdDataVo.kt
index 35b228b..8f680b5 100644
--- a/src/main/kotlin/com/flightfeather/obd/lightshare/bean/ObdDataVo.kt
+++ b/src/main/kotlin/com/flightfeather/obd/lightshare/bean/ObdDataVo.kt
@@ -22,7 +22,7 @@
     var obdEngineTorque: Double? = null
     var obdFrictionTorque: Double? = null
     var obdEngineRpm: Int? = null
-    var obdStartFuelFlow: Double? = null
+    var obdEngineFuelFlow: Double? = null
     var obdScrUpstreamNo: Double? = null
     var obdScrDownstreamNo: Double? = null
     var obdRemainReactant: Double? = null
diff --git a/src/main/kotlin/com/flightfeather/obd/repository/ObdDataRepository.kt b/src/main/kotlin/com/flightfeather/obd/repository/ObdDataRepository.kt
index 04bea7a..97e678d 100644
--- a/src/main/kotlin/com/flightfeather/obd/repository/ObdDataRepository.kt
+++ b/src/main/kotlin/com/flightfeather/obd/repository/ObdDataRepository.kt
@@ -3,6 +3,7 @@
 import com.flightfeather.obd.domain.entity.ObdData
 import com.flightfeather.obd.domain.mapper.ObdDataMapper
 import com.flightfeather.obd.lightshare.bean.ObdDataVo
+import com.flightfeather.obd.socket.bean.ObdPackageData
 import org.springframework.beans.BeanUtils
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Component
@@ -23,4 +24,7 @@
      * 閫氳繃姹借溅vin鐮佽幏鍙栨渶鏂版暟鎹�
      */
     fun getDataByVinCode(vinCode: String, pageNum: Int?, pageSize: Int?): MutableList<ObdDataVo>
+
+    fun saveObdData(packageData: ObdPackageData):Boolean
+
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/repository/impl/ObdDataDaoImpl.kt b/src/main/kotlin/com/flightfeather/obd/repository/impl/ObdDataDaoImpl.kt
index 4b49491..4abd7af 100644
--- a/src/main/kotlin/com/flightfeather/obd/repository/impl/ObdDataDaoImpl.kt
+++ b/src/main/kotlin/com/flightfeather/obd/repository/impl/ObdDataDaoImpl.kt
@@ -4,6 +4,10 @@
 import com.flightfeather.obd.domain.mapper.ObdDataMapper
 import com.flightfeather.obd.lightshare.bean.ObdDataVo
 import com.flightfeather.obd.repository.ObdDataRepository
+import com.flightfeather.obd.socket.bean.EngineDataFlow
+import com.flightfeather.obd.socket.bean.ObdPackageData
+import com.flightfeather.obd.socket.bean.SupplementDataFlow
+import com.flightfeather.obd.socket.eunm.ObdCommandUnit
 import com.github.pagehelper.PageHelper
 import org.springframework.beans.BeanUtils
 import org.springframework.stereotype.Repository
@@ -43,4 +47,77 @@
 
         return resultList
     }
+
+    override fun saveObdData(packageData: ObdPackageData): Boolean {
+        val obdData = ObdData().apply {
+            obdVin = packageData.vinCode
+        }
+        when (packageData.commandUnit) {
+            ObdCommandUnit.CarRegister.value -> {
+
+            }
+            ObdCommandUnit.RealTimeData.value,
+            ObdCommandUnit.ReplacementData.value -> {
+                packageData.dataUnit.forEach {
+                    when (it) {
+                        is com.flightfeather.obd.socket.bean.ObdData -> {
+                            obdData.apply {
+                                obdTime = it.time
+                                obdProtocol = it.obdProtocol
+                                obdMil = it.obdMil
+                                obdIdCode = it.obdSoftwareCode
+                                obdVerificationCode = it.obdCvn
+                                obdFaultCodeNum = it.obdFaultCodeNum
+                                obdFaultCode = it.obdFaultCode
+                            }
+                        }
+                        is EngineDataFlow -> {
+                            obdData.apply {
+                                obdLng = it.obdLong
+                                obdLat = it.obdLat
+                                obdSpeed = it.obdSpeed?.toInt()
+                                obdAirPressure = it.obdAirPressure
+                                obdEngineTorque = it.obdEngineTorque
+                                obdFrictionTorque = it.obdFrictionTorque
+                                obdEngineRpm = it.obdEngineRpm?.toInt()
+                                obdStartFuelFlow = it.obdEngineFuelFlow
+                                obdScrUpstreamNo = it.obdScrUpstreamNo
+                                obdScrDownstreamNo = it.obdScrDownstreamNo
+                                obdRemainReactant = it.obdRemainReactant
+                                obdAirInput = it.obdAirInput
+                                obdScrInputTemp = it.obdScrInputTemp
+                                obdScrOutputTemp = it.obdScrOutputTemp
+                                obdDpf = it.obdDpf
+                                obdEngineCoolantTemp = it.obdEngineCoolantTemp
+                                obdFuelLevel = it.obdFuelLevel
+                                obdLocationStatus = it.obdLocationStatus
+                                obdTotalMileage = it.obdTotalMileage
+                            }
+                        }
+                        is SupplementDataFlow -> {
+                            obdData.apply {
+                                obdEngineTorqueMode = it.obdEngineTorqueMode?.toString()
+                                obdAcceleratorPedal = it.obdAcceleratorPedal
+                                obdTotalOilConsumption = it.obdTotalOilConsumption
+                                obdUreaBoxTemp = it.obdUreaBoxTemp
+                                obdUreaVolume = it.obdUreaVolume?.toInt()
+                                obdTotalUreaConsume = it.obdTotalUreaConsume
+                                obdDpfTemp = it.obdDpfTemp
+//                                obdFirmwareVersion =
+                            }
+                        }
+                    }
+                }
+
+            }
+            ObdCommandUnit.CarLogOut.value -> {
+
+            }
+            ObdCommandUnit.TimeCalibration.value -> {
+
+            }
+        }
+
+        return obdDataMapper.insert(obdData) == 1
+    }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/MessageManager.kt b/src/main/kotlin/com/flightfeather/obd/socket/MessageManager.kt
index b709839..6f1a280 100644
--- a/src/main/kotlin/com/flightfeather/obd/socket/MessageManager.kt
+++ b/src/main/kotlin/com/flightfeather/obd/socket/MessageManager.kt
@@ -1,12 +1,15 @@
 package com.flightfeather.obd.socket
 
+import com.flightfeather.obd.common.utils.FileUtil
 import com.flightfeather.obd.lightshare.bean.BaseJson
 import com.flightfeather.obd.lightshare.bean.ObdDataVo
 import com.flightfeather.obd.repository.ObdDataRepository
+import com.flightfeather.obd.socket.decoder.VehicleDataDecoder
 import com.google.gson.Gson
 import io.netty.channel.ChannelHandlerContext
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Component
+import org.springframework.util.FileSystemUtils
 import javax.annotation.PostConstruct
 import javax.annotation.Resource
 
@@ -26,24 +29,38 @@
     @Autowired
     lateinit var obdDataRepository: ObdDataRepository
 
+    val vehicleDataDecoder = VehicleDataDecoder()
+
     @PostConstruct
     fun init() {
         instance = this
         instance.obdDataRepository = this.obdDataRepository
     }
 
-    fun dealMsg(msg: String, ctx: ChannelHandlerContext?) {
-        try {
-            val baseJson = Gson().fromJson<BaseJson>(msg, BaseJson::class.java)
-            when (baseJson.cmdCode) {
-                2001 -> {
-                    val data = Gson().fromJson(msg, ObdDataVo::class.java)
-                    DeviceSession.saveDevice(data.obdVin, ctx)
-                    instance.obdDataRepository.saveObdData(data)
-                }
-            }
-        } catch (e: Throwable) {
-//            println("------鏀跺埌鏍煎紡閿欒鐨勬暟鎹細$msg")
-        }
+    fun dealStringMsg(msg: String, ctx: ChannelHandlerContext?) {
+//        try {
+//            val baseJson = Gson().fromJson<BaseJson>(msg, BaseJson::class.java)
+//            when (baseJson.cmdCode) {
+//                2001 -> {
+//                    val data = Gson().fromJson(msg, ObdDataVo::class.java)
+//                    DeviceSession.saveDevice(data.obdVin, ctx)
+//                    instance.obdDataRepository.saveObdData(data)
+//                }
+//            }
+//        } catch (e: Throwable) {
+//        }
+
+        saveToTxt(msg)
+        val packageData = vehicleDataDecoder.decode(msg)
+    }
+
+    fun dealByteArrayMsg(msg: ByteArray, ctx: ChannelHandlerContext?) {
+        val b = ByteArray(20) {19}
+        println(b)
+    }
+
+    fun saveToTxt(msg: String) {
+        val data = "data=> $msg"
+        FileUtil.instance?.saveObdData(data)
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/ServerHandler.kt b/src/main/kotlin/com/flightfeather/obd/socket/ServerHandler.kt
index a71b02e..d904bca 100644
--- a/src/main/kotlin/com/flightfeather/obd/socket/ServerHandler.kt
+++ b/src/main/kotlin/com/flightfeather/obd/socket/ServerHandler.kt
@@ -3,6 +3,9 @@
 import io.netty.channel.ChannelHandlerContext
 import io.netty.channel.ChannelInboundHandlerAdapter
 import io.netty.util.AttributeKey
+import java.lang.StringBuilder
+import java.text.SimpleDateFormat
+import java.util.*
 
 
 class ServerHandler : ChannelInboundHandlerAdapter() {
@@ -11,6 +14,7 @@
 
     override fun channelRegistered(ctx: ChannelHandlerContext?) {
         super.channelRegistered(ctx)
+//        ctx?.fireChannelActive()
     }
 
     override fun channelActive(ctx: ChannelHandlerContext?) {
@@ -19,16 +23,27 @@
 
     override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) {
         super.channelRead(ctx, msg)
-        println("------鏀跺埌鐨勫師濮嬫暟鎹細[ip:${ctx?.channel()?.remoteAddress()}]\r\n$msg")
-        if (msg is String) {
-            MessageManager().dealMsg(msg, ctx)
-        }
 
-//        val attribute = ctx?.channel()?.attr(attributeKey)?.apply {
-//            if (get() == null) {
-//                set(data.obdVin)
-//            }
-//        }
+        val sb = StringBuilder()
+
+        if (msg is ByteArray) {
+            println("------鏀跺埌鐨勫師濮嬫暟鎹細[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
+            msg.forEach {
+                var a = 0
+                a = if (it < 0) {
+                    it + 256
+                } else {
+                    it.toInt()
+                }
+                print("${a.toString(16)} ")
+                sb.append(a.toString(16)).append(" ")
+            }
+            sb.deleteCharAt(sb.length - 1)
+        }
+        val str = sb.toString()
+        if (str.isNotEmpty()) {
+            MessageManager().dealStringMsg(str, ctx)
+        }
 
     }
 
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/SocketServerClient.kt b/src/main/kotlin/com/flightfeather/obd/socket/SocketServerClient.kt
index 4c1f489..991a4e7 100644
--- a/src/main/kotlin/com/flightfeather/obd/socket/SocketServerClient.kt
+++ b/src/main/kotlin/com/flightfeather/obd/socket/SocketServerClient.kt
@@ -4,10 +4,12 @@
 import io.netty.channel.ChannelInitializer
 import io.netty.channel.ChannelOption
 import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
 import io.netty.channel.socket.nio.NioServerSocketChannel
 import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
 import io.netty.handler.codec.string.StringDecoder
+import io.netty.handler.codec.string.StringEncoder
 
 /**
  * socket闀胯繛鎺ユ湇鍔$
@@ -34,15 +36,19 @@
             return ServerBootstrap()
                     .group(bossGroup, workerGroup)
                     .channel(NioServerSocketChannel::class.java)
+                    .option(ChannelOption.SO_BACKLOG, 128)
+                    .childOption(ChannelOption.SO_KEEPALIVE, true)
+                    .childOption(ChannelOption.TCP_NODELAY, true)
                     .childHandler(object : ChannelInitializer<NioSocketChannel>() {
                         override fun initChannel(p0: NioSocketChannel?) {
                             p0?.pipeline()
-                                    ?.addLast(StringDecoder())
+//                                    ?.addLast("decoder", StringDecoder())
+//                                    ?.addLast("encoder", StringEncoder())
+                                    ?.addLast(ByteArrayDecoder())
+                                    ?.addLast(ByteArrayEncoder())
                                     ?.addLast(ServerHandler())
                         }
                     })
-                    .option(ChannelOption.SO_BACKLOG, 128)
-                    .childOption(ChannelOption.SO_KEEPALIVE, true)
         } catch (e: Throwable) {
             e.printStackTrace()
         }
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/CarLogOutData.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/CarLogOutData.kt
new file mode 100644
index 0000000..954fdfd
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/CarLogOutData.kt
@@ -0,0 +1,14 @@
+package com.flightfeather.obd.socket.bean
+
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/12
+ * 杞﹁締鐧诲嚭淇℃伅
+ *
+ */
+class CarLogOutData(
+        var time: Date? = null,
+        var serialNum: Int? = null
+): DataUnit()
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/CarRegisterData.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/CarRegisterData.kt
new file mode 100644
index 0000000..e06beae
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/CarRegisterData.kt
@@ -0,0 +1,20 @@
+package com.flightfeather.obd.socket.bean
+
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/12
+ *
+ * 杞﹁締鐧诲叆鏁版嵁鏍煎紡
+ *
+ * 璧峰瀛楄妭        鍐呭                               鎻忚堪
+ * 0                    鏁版嵁閲囬泦鏃堕棿                 鏃堕棿瀹氫箟瑙� 6.4.4
+ * 6                    鐧诲叆娴佹按鍙�                   杞﹁浇缁堢姣忕櫥鍏ヤ竴娆★紝鐧诲叆娴佹按鍙疯嚜鍔ㄥ姞 1锛屼粠 1寮�濮嬪惊鐜疮鍔狅紝鏈�澶у�间负 65531锛屽惊鐜懆鏈熶负澶┿��
+ * 10                  SIM 鍗″彿                       SIM 鍗� ICCID 鍙凤紙ICCID 搴斾负缁堢浠� SIM 鍗¤幏鍙栫殑鍊硷紝涓嶅簲浜轰负濉啓鎴栦慨鏀癸級銆�
+ */
+class CarRegisterData(
+        var time: Date? = null,
+        var serialNum: Int? = null,
+        var SIMCode: String? = null
+): DataUnit()
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/DataUnit.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/DataUnit.kt
new file mode 100644
index 0000000..b63c8d1
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/DataUnit.kt
@@ -0,0 +1,8 @@
+package com.flightfeather.obd.socket.bean
+
+/**
+ * @author riku
+ * Date: 2019/9/12
+ */
+open class DataUnit {
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/EngineDataFlow.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/EngineDataFlow.kt
new file mode 100644
index 0000000..12ff10c
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/EngineDataFlow.kt
@@ -0,0 +1,33 @@
+package com.flightfeather.obd.socket.bean
+
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/15
+ * 鍙戝姩鏈烘暟鎹祦
+ */
+class EngineDataFlow(
+        time: Date?,
+        serialNum: Int?
+) : RealTimeData(time, serialNum) {
+    var obdSpeed: Double? = null
+    var obdAirPressure: Double? = null
+    var obdEngineTorque: Double? = null
+    var obdFrictionTorque: Double? = null
+    var obdEngineRpm: Double? = null
+    var obdEngineFuelFlow: Double? = null
+    var obdScrUpstreamNo: Double? = null
+    var obdScrDownstreamNo: Double? = null
+    var obdRemainReactant: Double? = null
+    var obdAirInput: Double? = null
+    var obdScrInputTemp: Double? = null
+    var obdScrOutputTemp: Double? = null
+    var obdDpf: Double? = null
+    var obdEngineCoolantTemp: Double? = null
+    var obdFuelLevel: Double? = null
+    var obdLocationStatus: Int? = null
+    var obdLong: Double? = null
+    var obdLat: Double? = null
+    var obdTotalMileage: Double? = null
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/ObdData.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/ObdData.kt
new file mode 100644
index 0000000..817accf
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/ObdData.kt
@@ -0,0 +1,25 @@
+package com.flightfeather.obd.socket.bean
+
+import com.flightfeather.obd.socket.bean.*
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/15
+ * 瀹炴椂淇℃伅[RealTimeData] 涓殑obd鏁版嵁
+ */
+class ObdData(
+        time: Date?,
+        serialNum: Int?
+) : RealTimeData(time, serialNum) {
+    var obdProtocol: Int? = null
+    var obdMil: Int? = null
+    var diagnosisSupportStatus: String? = null//璇婃柇鏀寔鐘舵��
+    var diagnosisReadyStatus: String? = null//璇婃柇灏辩华鐘舵��
+    var obdVin: String? = null
+    var obdSoftwareCode: String? = null//杞欢鏍囧畾璇嗗埆鍙�
+    var obdCvn: String? = null//鏍囧畾楠岃瘉鐮�
+    var IUPR:String?=null//瀹氫箟鍙傝�� SAE J 1979-DA 琛� G11
+    var obdFaultCodeNum: Int? = null//鏁呴殰鐮佹�绘暟: 鏈夋晥鍊艰寖鍥达細0~253锛屸��0xFE鈥濊〃绀烘棤鏁堛��
+    var obdFaultCode: String? = null//鏁呴殰鐮佷俊鎭垪琛�: 姣忎釜鏁呴殰鐮佷负鍥涘瓧鑺傦紝鍙寜鏁呴殰瀹為檯椤哄簭杩涜鎺掑簭
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/ObdPackageData.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/ObdPackageData.kt
new file mode 100644
index 0000000..838a048
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/ObdPackageData.kt
@@ -0,0 +1,16 @@
+package com.flightfeather.obd.socket.bean
+
+/**
+ * @author riku
+ * Date: 2019/9/12
+ */
+data class ObdPackageData constructor(
+        var head: String? = null,
+        var commandUnit: Int? = null,
+        var vinCode: String? = null,
+        var softwareVersion: Int? = null,
+        var encryptionWay: Int? = null,
+        var dataLength: Int? = null,
+        var dataUnit: List<DataUnit>,
+        var checkCode: Int? = null
+)
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/RealTimeData.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/RealTimeData.kt
new file mode 100644
index 0000000..619c311
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/RealTimeData.kt
@@ -0,0 +1,13 @@
+package com.flightfeather.obd.socket.bean
+
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/12
+ *
+ */
+open class RealTimeData(
+        var time: Date? = null,
+        var serialNum: Int? = null
+) : ReplacementData()
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/ReplacementData.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/ReplacementData.kt
new file mode 100644
index 0000000..e5f8b6b
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/ReplacementData.kt
@@ -0,0 +1,9 @@
+package com.flightfeather.obd.socket.bean
+
+/**
+ * @author riku
+ * Date: 2019/9/12
+ * 琛ュ彂淇℃伅涓庡疄鏃朵俊鎭唴瀹逛竴鑷�
+ */
+open class ReplacementData : DataUnit() {
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/SupplementDataFlow.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/SupplementDataFlow.kt
new file mode 100644
index 0000000..b5bf0f1
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/SupplementDataFlow.kt
@@ -0,0 +1,57 @@
+package com.flightfeather.obd.socket.bean
+
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/15
+ * 琛ュ厖鏁版嵁娴�
+ *
+ * 璧峰瀛楄妭      鏁版嵁椤�                            鏁版嵁绫诲瀷        鍗曚綅          鎻忚堪鍙婅姹�
+ * 0                 鍙戝姩鏈烘壄鐭╂ā寮�                BYTE                            0锛氳秴閫熷け鏁�
+ *                                                                                                  1锛氳浆閫熸帶鍒�
+ *                                                                                                  2锛氭壄鐭╂帶鍒�
+ *                                                                                                  3锛氳浆閫�/鎵煩鎺у埗
+ * 1                  娌归棬韪忔澘                          BYTE               %           鏁版嵁闀垮害锛�1bytes
+ *                                                                                                  绮惧害锛�0.4%/bit
+ *                                                                                                  鍋忕Щ閲忥細0
+ *                                                                                                  鏁版嵁鑼冨洿锛�0~100%
+ *                                                                                                  鈥�0xFF鈥濊〃绀烘棤鏁�
+ * 2                绱娌硅�楋紙鎬绘补鑰楋級          DWORD           L           鏁版嵁闀垮害锛�4bytes
+ *                                                                                                  绮惧害锛�0.5L per bit
+ *                                                                                                  鍋忕Щ閲忥細0
+ *                                                                                                  鏁版嵁鑼冨洿锛�0~2,105,540,607.5L
+ *                                                                                                  鈥�0xFF,0xFF,0xFF,0xFF鈥濊〃绀烘棤鏁�
+ * 6                  灏跨礌绠辨俯搴�                      BYTE               鈩�          鏁版嵁闀垮害锛�1bytes
+ *                                                                                                  绮惧害锛�1 鈩�/bit
+ *                                                                                                  鍋忕Щ閲忥細-40
+ *                                                                                                  鏁版嵁鑼冨洿锛�-40~210鈩�
+ *                                                                                                  鈥�0xFF鈥濊〃绀烘棤鏁�
+ * 7                   瀹為檯灏跨礌鍠峰皠閲�              DWORD         ml/h       鏁版嵁闀垮害锛�4bytes
+ *                                                                                                  绮惧害锛�0.01 ml/h per bit
+ *                                                                                                  鍋忕Щ閲忥細0
+ *                                                                                                  鏁版嵁鑼冨洿锛�0
+ *                                                                                                  鈥�0xFF,0xFF,0xFF,0xFF鈥濊〃绀烘棤鏁�
+ * 11                   绱灏跨礌娑堣�楋紙鎬诲翱绱犳秷鑰楋級DWORD      g        鏁版嵁闀垮害锛�4bytes
+ *                                                                                                  绮惧害锛�1 g per bit
+ *                                                                                                  鍋忕Щ閲忥細0
+ *                                                                                                  鏁版嵁鑼冨洿锛�0
+ *                                                                                                  鈥�0xFF,0xFF,0xFF,0xFF鈥濊〃绀烘棤鏁�
+ * 15                   DPF 鎺掓皵娓╁害                  WORD             鈩�        鏁版嵁闀垮害锛�2bytes
+ *                                                                                                   绮惧害锛�0.03125 鈩� per bit
+ *                                                                                                   鍋忕Щ閲忥細-273
+ *                                                                                                   鏁版嵁鑼冨洿锛�-273~1734.96875鈩�
+ *                                                                                                   鈥�0xFF,0xFF鈥濊〃绀烘棤鏁�
+ */
+class SupplementDataFlow(
+        time: Date?,
+        serialNum: Int?
+) : RealTimeData(time, serialNum) {
+    var obdEngineTorqueMode: Int? = null
+    var obdAcceleratorPedal: Double? = null
+    var obdTotalOilConsumption: Double? = null
+    var obdUreaBoxTemp: Double? = null
+    var obdUreaVolume: Double? = null
+    var obdTotalUreaConsume: Double? = null
+    var obdDpfTemp: Double? = null
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/bean/TimeCalibrationData.kt b/src/main/kotlin/com/flightfeather/obd/socket/bean/TimeCalibrationData.kt
new file mode 100644
index 0000000..b94fde1
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/bean/TimeCalibrationData.kt
@@ -0,0 +1,8 @@
+package com.flightfeather.obd.socket.bean
+
+/**
+ * @author riku
+ * Date: 2019/9/12
+ */
+class TimeCalibrationData : DataUnit() {
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/decoder/DataPackageDecoder.kt b/src/main/kotlin/com/flightfeather/obd/socket/decoder/DataPackageDecoder.kt
new file mode 100644
index 0000000..589ab12
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/decoder/DataPackageDecoder.kt
@@ -0,0 +1,42 @@
+package com.flightfeather.obd.socket.decoder
+
+import com.flightfeather.obd.socket.bean.DataUnit
+import com.flightfeather.obd.socket.eunm.ObdCommandUnit
+
+/**
+ * obd 绗竴灞傛暟鎹寘瑙g爜鍣�
+ * @author riku
+ * Date: 2019/9/12
+ *
+ * 鏁版嵁绗竴灞傜粨鏋勫畾涔夊涓嬶細
+ * 璧峰瀛楄妭         瀹氫箟
+ * 0                    璧峰绗�
+ * 2                    鍛戒护鍗曞厓  绫诲瀷@see [ObdCommandUnit]
+ * 3                    杞﹁締璇嗗埆鍙�
+ * 4                    缁堢杞欢鐗堟湰鍙�
+ * 21                   鏁版嵁鍔犲瘑鏂瑰紡
+ * 22                   鏁版嵁鍗曞厓闀垮害
+ * 24                   鏁版嵁鍗曞厓  瑙g爜鍣ˊsee [DataUnitDecoder]
+ * 鍊掓暟绗�1           鏍¢獙鐮�
+ */
+interface DataPackageDecoder {
+
+    fun getHead(b: List<String>): String?
+
+    fun getCommandUnit(b: List<String>): Int?
+
+    fun getVinCode(b: List<String>): String?
+
+    fun getSoftwareVersion(b: List<String>): Int?
+
+    fun getEncryptionWay(b: List<String>): Int?
+
+    fun getDataLength(b: List<String>): Int
+
+    fun getDataUnit(b: List<String>): List<DataUnit>
+
+    fun getCheckCode(b: List<String>): Int?
+
+    fun toStringList(msg: String): List<String>
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/decoder/DataUnitDecoder.kt b/src/main/kotlin/com/flightfeather/obd/socket/decoder/DataUnitDecoder.kt
new file mode 100644
index 0000000..7ca4833
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/decoder/DataUnitDecoder.kt
@@ -0,0 +1,36 @@
+package com.flightfeather.obd.socket.decoder
+
+import com.flightfeather.obd.socket.bean.*
+import com.flightfeather.obd.socket.eunm.ObdCommandUnit
+import java.util.*
+
+/**
+ * obd 绗簩灞傛暟鎹崟鍏冭В鐮佸櫒
+ * @author riku
+ * Date: 2019/9/12
+ *
+ * 鏁版嵁鍗曞厓鎸夌収鍛戒护鍗曞厓鐨勭被鍨嬪叡鏈変互涓嬪嚑绉嶇被鍨嬶細
+ * 鍛戒护鍗曞厓 @see [ObdCommandUnit]
+ * 缂栫爜(byte)        瀹氫箟
+ * 0x01                 杞﹁締鐧诲叆
+ * 0x02                 瀹炴椂淇℃伅涓婃姤
+ * 0x03                 琛ュ彂淇℃伅涓婃姤
+ * 0x04                 杞﹁締鐧诲嚭
+ * 0x05                 缁堢鏍℃椂
+ * 0x06~0x7f       涓婅鏁版嵁绯荤粺棰勭暀
+ */
+interface DataUnitDecoder {
+
+    fun getCarRegisterData(b: List<String>): List<CarRegisterData>
+
+    fun getRealTimeData(b: List<String>): List<RealTimeData>
+
+    fun getReplacementData(b: List<String>): List<ReplacementData>
+
+    fun getCarLogOutData(b: List<String>): List<CarLogOutData>
+
+    fun getTimeCalibrationData(b: List<String>): List<TimeCalibrationData>
+
+    fun decodeDataTime(b: List<String>): Date?
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/decoder/RealTimeDataDecoder.kt b/src/main/kotlin/com/flightfeather/obd/socket/decoder/RealTimeDataDecoder.kt
new file mode 100644
index 0000000..24e41e0
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/decoder/RealTimeDataDecoder.kt
@@ -0,0 +1,26 @@
+package com.flightfeather.obd.socket.decoder
+
+import com.flightfeather.obd.socket.bean.*
+import com.flightfeather.obd.socket.eunm.ObdDataType
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/15
+ * 鏁版嵁鍗曞厓[DataUnit]涓紝绫诲瀷涓哄疄鏃朵俊鎭痆RealTimeData]鐨勮В鐮佸櫒
+ * 鍏跺垎绫� @see [ObdDataType]
+ */
+interface RealTimeDataDecoder {
+
+    fun getObdData(time: Date?, serialNum: Int, b: List<String>): ObdData?
+
+    fun getEngineDataFlow(time: Date?, serialNum: Int, b: List<String>): EngineDataFlow?
+
+    fun getSupplementDataFlow(time: Date?, serialNum: Int, b: List<String>): SupplementDataFlow?
+
+    /**
+     * 鏍规嵁浼犲叆鐨勫垪琛紝榛樿绗竴浣嶄负 [ObdDataType]锛岃繑鍥炲搴旂殑鏁版嵁鍒楄〃
+     */
+    fun getDataListByDataType(list: List<String>): MutableList<String>
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/decoder/VehicleDataDecoder.kt b/src/main/kotlin/com/flightfeather/obd/socket/decoder/VehicleDataDecoder.kt
new file mode 100644
index 0000000..64aaf75
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/decoder/VehicleDataDecoder.kt
@@ -0,0 +1,35 @@
+package com.flightfeather.obd.socket.decoder
+
+import com.flightfeather.obd.socket.bean.ObdPackageData
+import com.flightfeather.obd.socket.decoder.impl.DataPackageDecoderImpl
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Component
+import javax.annotation.PostConstruct
+
+/**
+ * 杞﹁締 obd 鏁版嵁瑙g爜鍣�
+ * @author riku
+ * Date: 2019/9/12
+ */
+class VehicleDataDecoder {
+
+    private val dataPackageDecoder: DataPackageDecoder = DataPackageDecoderImpl()
+
+    fun decode(msg: String): ObdPackageData {
+        val list = dataPackageDecoder.toStringList(msg)
+        dataPackageDecoder.run {
+            return ObdPackageData(
+                    getHead(list),
+                    getCommandUnit(list),
+                    getVinCode(list),
+                    getSoftwareVersion(list),
+                    getEncryptionWay(list),
+                    getDataLength(list),
+                    getDataUnit(list),
+                    getCheckCode(list)
+            )
+        }
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/DataPackageDecoderImpl.kt b/src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/DataPackageDecoderImpl.kt
new file mode 100644
index 0000000..5df0e21
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/DataPackageDecoderImpl.kt
@@ -0,0 +1,98 @@
+package com.flightfeather.obd.socket.decoder.impl
+
+import com.flightfeather.obd.socket.bean.DataUnit
+import com.flightfeather.obd.socket.decoder.DataPackageDecoder
+import com.flightfeather.obd.socket.decoder.DataUnitDecoder
+import com.flightfeather.obd.socket.eunm.ObdCommandUnit
+
+/**
+ * @author riku
+ * Date: 2019/9/12
+ */
+class DataPackageDecoderImpl : DataPackageDecoder {
+
+    private val dataUnitDecoder: DataUnitDecoder = DataUnitDecoderImpl()
+
+    //fixme 2019.9.12: 鐜板湪鏈変袱绉嶆儏鍐碉紝1锛氭帴鏀跺埌鐨勫瓧绗︿覆鏄痓yte杞爜鍓嶇殑锛岄偅涔堝叾灏辫〃绀哄瓧绗︾殑ASCII鐮侊紱2锛氬彟涓�绉嶅氨鏄帴鏀跺埌鐨勬槸杞爜鍚庣殑瀛楃涓层�傜洰鍓嶅緟瀹�
+
+    override fun getHead(b: List<String>): String? {
+        return if (b.size >= 2) {
+            "${b[0]}${b[1]}"
+        } else {
+            null
+        }
+    }
+
+    override fun getCommandUnit(b: List<String>): Int? = if (b.size >= 3) {
+        b[2].toIntOrNull(16)
+    } else {
+        null
+    }
+
+    override fun getVinCode(b: List<String>): String? {
+        if (b.size < 20) return null
+
+        //fixme 搴旇鏄渶瑕佸皢b褰撲綔ASCII鐮侊紝鍐嶈幏鍙栬浆鎹㈠悗鐨勫瓧绗︿覆
+        val s = StringBuilder()
+
+        for (i in 3..19) {
+            s.append(b[i].toIntOrNull(16)?.toChar())
+        }
+
+        return s.toString()
+    }
+
+    override fun getSoftwareVersion(b: List<String>): Int? = if (b.size >= 21) {
+        b[20].toIntOrNull(16)
+    } else {
+        null
+    }
+
+    override fun getEncryptionWay(b: List<String>): Int? = if (b.size >= 21) {
+        b[21].toIntOrNull(16)
+    } else {
+        null
+    }
+
+    override fun getDataLength(b: List<String>): Int {
+        if (b.size < 24) return 0
+
+        val hexNum = "${b[22]}${b[23]}"
+
+        return hexNum.toIntOrNull(16) ?: 0
+    }
+
+    override fun getDataUnit(b: List<String>): List<DataUnit> {
+        if (getDataLength(b) == 0 || b.size < 26) {
+            return emptyList()
+        }
+
+        val unit = mutableListOf<String>()
+        for (i in 24..b.size - 2) {
+            unit.add(b[i])
+        }
+        dataUnitDecoder.run {
+            return when (getCommandUnit(b)) {
+                ObdCommandUnit.CarRegister.value -> getCarRegisterData(unit)
+                ObdCommandUnit.RealTimeData.value -> getRealTimeData(unit)
+                ObdCommandUnit.ReplacementData.value -> getReplacementData(unit)
+                ObdCommandUnit.CarLogOut.value -> getCarLogOutData(unit)
+                ObdCommandUnit.TimeCalibration.value -> getTimeCalibrationData(unit)
+                else -> emptyList()
+            }
+        }
+    }
+
+    override fun getCheckCode(b: List<String>): Int? {
+        return if (b.isNotEmpty()) {
+            b[b.size - 1].toIntOrNull(16)
+        } else {
+            null
+        }
+    }
+
+    override fun toStringList(msg: String): List<String> {
+        return msg.split(" ")
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/DataUnitDecoderImpl.kt b/src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/DataUnitDecoderImpl.kt
new file mode 100644
index 0000000..139051c
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/DataUnitDecoderImpl.kt
@@ -0,0 +1,123 @@
+package com.flightfeather.obd.socket.decoder.impl
+
+import com.flightfeather.obd.socket.bean.*
+import com.flightfeather.obd.socket.decoder.DataUnitDecoder
+import com.flightfeather.obd.socket.decoder.RealTimeDataDecoder
+import com.flightfeather.obd.socket.eunm.ObdDataType
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Component
+import java.lang.StringBuilder
+import java.util.*
+import javax.annotation.PostConstruct
+
+/**
+ * @author riku
+ * Date: 2019/9/15
+ */
+class DataUnitDecoderImpl : DataUnitDecoder {
+
+    private var realTimeDataDecoder: RealTimeDataDecoder = RealTimeDataDecoderImpl()
+
+    override fun getCarRegisterData(b: List<String>): List<CarRegisterData> {
+        val time = decodeDataTime(b)
+
+        val serialNum = "${b[6]}${b[7]}".toInt(16)
+
+        val simCode = StringBuilder()
+        for (i in 10 until b.size) {
+            simCode.append(b[i].toInt(16).toChar())
+        }
+
+        return mutableListOf(CarRegisterData(time, serialNum, simCode.toString()))
+    }
+
+    override fun getRealTimeData(b: List<String>): List<RealTimeData> {
+        val time = decodeDataTime(b)
+
+        //鍥芥爣娉�: 璧峰瀛楄妭涓�7 寮�濮嬬殑2涓瓧鑺傝〃绀� 娴佹按鍙�
+//        val serialNum = "${b[7]}${b[8]}".toInt(16)
+
+        //涓婃捣娉�: 璧峰瀛楄妭涓�6 寮�濮嬬殑2涓瓧鑺傝〃绀� 娴佹按鍙�
+        val serialNum = "${b[6]}${b[7]}".toInt(16)
+
+        val dataList = mutableListOf<String>().apply { addAll(b) }
+        //鍒犲幓鍓�6浣嶆椂闂�
+        for (i in 0..5) {
+            if (dataList.isNotEmpty()) dataList.removeAt(0)
+        }
+
+        //fixme 2019.9.15 鐩墠涓ょ瑙勫垯鏈夊啿绐侊紝骞朵笖鍙粠鏁版嵁鍐呭鏃犳硶鍖哄垎銆傛殏鏃朵娇鐢� 鍥芥爣娉�
+        /*
+        * 鍒犲幓娴佹按鍙凤紝寰楀埌淇℃伅鏍囧織涓庝俊鎭綋鐨勭粍鍚�
+        * (鍥芥爣娉曪細鍘婚櫎鍓�6浣嶆椂闂村悗锛岃捣濮嬪瓧鑺備负1 寮�濮嬬殑2涓瓧鑺傝〃绀� 娴佹按鍙�)
+        */
+//        if (dataList.size >= 2) dataList.removeAt(1)
+//        if (dataList.size >= 2) dataList.removeAt(1)
+
+        /*
+        * 鍒犲幓娴佹按鍙凤紝寰楀埌淇℃伅鏍囧織涓庝俊鎭綋鐨勭粍鍚�
+        * (涓婃捣娉曪細鍘婚櫎鍓�6浣嶆椂闂村悗锛岃捣濮嬪瓧鑺備负0 寮�濮嬬殑2涓瓧鑺傝〃绀� 娴佹按鍙�)
+        */
+        if (dataList.isNotEmpty()) dataList.removeAt(0)
+        if (dataList.isNotEmpty()) dataList.removeAt(0)
+
+        val resultList = mutableListOf<RealTimeData>()
+
+        /*
+         * 鏈�缁堝緱鍒扮殑鏁版嵁缁撴瀯涓� [ 淇℃伅绫诲瀷鏍囧織, 淇℃伅浣�, ...... , 淇℃伅绫诲瀷鏍囧織, 淇℃伅浣� ]
+         */
+        while (dataList.isNotEmpty()) {
+            //寰楀埌鏈�鍓嶉潰鐨勪竴缁勪俊鎭被鍨�+淇℃伅浣撳垪琛�
+            val data = realTimeDataDecoder.getDataListByDataType(dataList)
+            if (data.isNotEmpty()) {
+                val r = when (data[0].toInt(16)) {
+                    ObdDataType.ObdData.value -> realTimeDataDecoder.getObdData(time, serialNum, data)
+                    ObdDataType.EngineDataFlow.value -> realTimeDataDecoder.getEngineDataFlow(time, serialNum, data)
+                    ObdDataType.SupplementDataFlow.value -> realTimeDataDecoder.getSupplementDataFlow(time, serialNum, data)
+                    else -> null
+                }
+
+                if (r != null) {
+                    resultList.add(r)
+                }
+
+                for (i in 0 until data.size) {
+                    if (dataList.isNotEmpty()) dataList.removeAt(0)
+                }
+            }
+        }
+
+        return resultList
+    }
+
+    override fun getReplacementData(b: List<String>): List<ReplacementData> = getRealTimeData(b)
+
+    override fun getCarLogOutData(b: List<String>): List<CarLogOutData> {
+        val time = decodeDataTime(b)
+
+        val serialNum = "${b[6]}${b[7]}".toInt(16)
+
+        return mutableListOf(CarLogOutData(time, serialNum))
+    }
+
+    override fun getTimeCalibrationData(b: List<String>): List<TimeCalibrationData> = emptyList()
+
+    override fun decodeDataTime(b: List<String>): Date? {
+        if (b.size < 6) {
+            return null
+        }
+
+        val year = b[0].toInt(16) + 2000
+        if (year < 2000 || year > 2099) return null
+        val month = b[1].toInt(16)
+        val day = b[2].toInt(16)
+        val hour = b[3].toInt(16)
+        val min = b[4].toInt(16)
+        val sec = b[5].toInt(16)
+        val cal  = Calendar.getInstance().apply {
+            set(year, month - 1, day, hour, min, sec)
+        }
+
+        return cal.time
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/RealTimeDataDecoderImpl.kt b/src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/RealTimeDataDecoderImpl.kt
new file mode 100644
index 0000000..3acf5e8
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/decoder/impl/RealTimeDataDecoderImpl.kt
@@ -0,0 +1,163 @@
+package com.flightfeather.obd.socket.decoder.impl
+
+import com.flightfeather.obd.socket.bean.EngineDataFlow
+import com.flightfeather.obd.socket.bean.ObdData
+import com.flightfeather.obd.socket.bean.SupplementDataFlow
+import com.flightfeather.obd.socket.decoder.RealTimeDataDecoder
+import com.flightfeather.obd.socket.eunm.ObdDataType
+import org.springframework.stereotype.Component
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/15
+ */
+class RealTimeDataDecoderImpl : RealTimeDataDecoder {
+    override fun getObdData(time: Date?, serialNum: Int, b: List<String>): ObdData? {
+        val dataList = mutableListOf<String>().apply { addAll(b) }
+        if (b.isNotEmpty()) {
+            //鍘婚櫎 淇℃伅绫诲瀷鏍囧織
+            dataList.removeAt(0)
+        }
+        if (dataList.size >= 96) {
+            val vin = StringBuilder()
+            for (i in 6..22) {
+                vin.append(dataList[i].toIntOrNull(16)?.toChar())
+            }
+            val softwareCode = StringBuilder()
+            for (i in 23..40) {
+                softwareCode.append(dataList[i].toIntOrNull(16)?.toChar())
+            }
+            val cvn = StringBuilder()
+            for (i in 41..58) {
+                cvn.append(dataList[i].toIntOrNull(16)?.toChar())
+            }
+            val IUPR = StringBuilder()
+            for (i in 59..94) {
+                //todo 2019.9.15 鍥犳殏涓嶆竻妤氭牸寮忎笌鍚箟锛岀洿鎺ヤ繚瀛�
+                IUPR.append(dataList[i])
+            }
+            var faultCodeNum = dataList[95].toIntOrNull() ?: 0
+            val faultCode = StringBuilder()
+            if (faultCodeNum < 0 || faultCodeNum > 253) {
+                faultCodeNum = 254//浠h〃鏃犳晥
+            } else {
+                for (i in 96..(95 + 4 * faultCodeNum)) {
+                    faultCode.append(dataList[i])
+                }
+            }
+
+            return ObdData(time, serialNum).apply {
+                obdProtocol = dataList[0].toIntOrNull(16)
+                obdMil = dataList[1].toIntOrNull(16)
+                diagnosisSupportStatus = "${dataList[2]}${dataList[3]}".toIntOrNull(16)?.toString(2)
+                diagnosisReadyStatus = "${dataList[4]}${dataList[5]}".toIntOrNull(16)?.toString(2)
+                obdVin = vin.toString()
+                obdSoftwareCode = softwareCode.toString()
+                obdCvn = cvn.toString()
+                this.IUPR = IUPR.toString()
+                obdFaultCodeNum = faultCodeNum
+                obdFaultCode = faultCode.toString()
+            }
+        } else {
+            return null
+        }
+    }
+
+    override fun getEngineDataFlow(time: Date?, serialNum: Int, b: List<String>): EngineDataFlow? {
+        val dataList = mutableListOf<String>().apply { addAll(b) }
+        if (b.isNotEmpty()) {
+            //鍘婚櫎 淇℃伅绫诲瀷鏍囧織
+            dataList.removeAt(0)
+        }
+
+        return if (dataList.size >= 37) {
+             EngineDataFlow(time, serialNum).apply {
+                obdSpeed = "${dataList[0]}${dataList[1]}".toIntOrNull(16)?.toDouble()?.times((1 / 256).toDouble())
+                obdAirPressure = dataList[2].toIntOrNull(16)?.toDouble()?.times(0.5)
+                obdEngineTorque = dataList[3].toIntOrNull(16)?.minus(125)?.toDouble()?.div(100)
+                obdFrictionTorque = dataList[4].toIntOrNull(16)?.minus(125)?.toDouble()?.div(100)
+                obdEngineRpm = "${dataList[5]}${dataList[6]}".toIntOrNull(16)?.toDouble()?.times(0.125)
+                obdEngineFuelFlow = "${dataList[7]}${dataList[8]}".toIntOrNull(16)?.toDouble()?.times(0.05)
+                obdScrUpstreamNo = "${dataList[9]}${dataList[10]}".toIntOrNull(16)?.minus(200)?.toDouble()?.times(0.05)
+                obdScrDownstreamNo = "${dataList[11]}${dataList[12]}".toIntOrNull(16)?.minus(200)?.toDouble()?.times(0.05)
+                obdRemainReactant = dataList[13].toIntOrNull(16)?.toDouble()?.times(0.4)?.div(100)
+                obdAirInput = "${dataList[14]}${dataList[15]}".toIntOrNull(16)?.toDouble()?.times(0.05)
+                obdScrInputTemp = "${dataList[16]}${dataList[17]}".toIntOrNull(16)?.minus(273)?.toDouble()?.times(0.03125)
+                obdScrOutputTemp = "${dataList[18]}${dataList[19]}".toIntOrNull(16)?.minus(273)?.toDouble()?.times(0.03125)
+                obdDpf = "${dataList[20]}${dataList[21]}".toIntOrNull(16)?.toDouble()?.times(0.1)
+                obdEngineCoolantTemp = dataList[22].toIntOrNull(16)?.minus(40)?.toDouble()
+                obdFuelLevel = dataList[23].toIntOrNull(16)?.toDouble()?.times(0.4)
+                obdLocationStatus = dataList[24].toIntOrNull(16)
+                obdLong = "${dataList[25]}${dataList[26]}${dataList[27]}${dataList[28]}".toIntOrNull(16)?.toDouble()?.times(0.000001)
+                obdLat = "${dataList[29]}${dataList[30]}${dataList[31]}${dataList[32]}".toIntOrNull(16)?.toDouble()?.times(0.000001)
+                obdTotalMileage = "${dataList[33]}${dataList[34]}${dataList[35]}${dataList[36]}".toIntOrNull(16)?.toDouble()?.times(0.1)
+            }
+        } else {
+            null
+        }
+    }
+
+    override fun getSupplementDataFlow(time: Date?, serialNum: Int, b: List<String>): SupplementDataFlow? {
+        val dataList = mutableListOf<String>().apply { addAll(b) }
+        if (b.isNotEmpty()) {
+            //鍘婚櫎 淇℃伅绫诲瀷鏍囧織
+            dataList.removeAt(0)
+        }
+
+        return if (dataList.size >= 17) {
+            SupplementDataFlow(time, serialNum).apply {
+                obdEngineTorqueMode = dataList[0].toIntOrNull(16)
+                obdAcceleratorPedal = dataList[1].toIntOrNull(16)?.toDouble()?.times(0.4)?.div(100)
+                obdTotalOilConsumption = "${dataList[2]}${dataList[3]}${dataList[4]}${dataList[5]}".toIntOrNull(16)?.toDouble()?.times(0.5)
+                obdUreaBoxTemp  = dataList[6].toIntOrNull(16)?.toDouble()?.minus(40)
+                obdUreaVolume  = "${dataList[7]}${dataList[8]}${dataList[9]}${dataList[10]}".toIntOrNull(16)?.toDouble()?.times(0.01)
+                obdTotalUreaConsume  = "${dataList[11]}${dataList[12]}${dataList[13]}${dataList[14]}".toIntOrNull(16)?.toDouble()
+                obdDpfTemp  = "${dataList[15]}${dataList[16]}".toIntOrNull(16)?.minus(273)?.toDouble()?.times(0.03125)
+            }
+        } else {
+            null
+        }
+    }
+
+    override fun getDataListByDataType(list: List<String>): MutableList<String> {
+        if (list.isEmpty()) return mutableListOf()
+
+        val resultList = mutableListOf<String>().apply {
+            //娣诲姞 淇℃伅绫诲瀷鏍囧織
+            add(list[0])
+        }
+
+        when (list[0].toIntOrNull(16)) {
+            ObdDataType.ObdData.value -> {
+                //浠庤捣濮嬪瓧鑺� 1 寮�濮嬶紝鍥哄畾鏈�97涓瓧鑺傜殑鏁版嵁
+                for (i in 1..96) {
+                    resultList.add(list[i])
+                }
+
+                val faultCodeNum = list[96].toIntOrNull() ?: 0//鏁呴殰鐮佹�绘暟
+                //鏍规嵁鏁呴殰鐮佹�绘暟锛屾瘡涓晠闅滅爜4涓瓧鑺傦紝寰楀埌鏁呴殰鐮佹�诲瓧鑺傛暟
+                if (faultCodeNum in 0..253) {
+                    for (i in 97..(96 + faultCodeNum * 4)) {
+                        resultList.add(list[i])
+                    }
+                }
+            }
+            ObdDataType.EngineDataFlow.value -> {
+                //浠庤捣濮嬪瓧鑺� 1 寮�濮嬶紝鍥哄畾鏈�37涓瓧鑺傜殑鏁版嵁
+                for (i in 1..37) {
+                    resultList.add(list[i])
+                }
+            }
+            ObdDataType.SupplementDataFlow.value -> {
+                //浠庤捣濮嬪瓧鑺� 1 寮�濮嬶紝鍥哄畾鏈�17涓瓧鑺傜殑鏁版嵁
+                for (i in 1..17) {
+                    resultList.add(list[i])
+                }
+            }
+        }
+
+        return resultList
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/eunm/ObdCommandUnit.kt b/src/main/kotlin/com/flightfeather/obd/socket/eunm/ObdCommandUnit.kt
new file mode 100644
index 0000000..c88fdc1
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/eunm/ObdCommandUnit.kt
@@ -0,0 +1,14 @@
+package com.flightfeather.obd.socket.eunm
+
+/**
+ * obd 鍛戒护鍗曞厓
+ * @author riku
+ * Date: 2019/9/12
+ */
+enum class ObdCommandUnit constructor(val value: Int) {
+    CarRegister(1),
+    RealTimeData(2),
+    ReplacementData(3),
+    CarLogOut(4),
+    TimeCalibration(5)
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/obd/socket/eunm/ObdDataType.kt b/src/main/kotlin/com/flightfeather/obd/socket/eunm/ObdDataType.kt
new file mode 100644
index 0000000..b426851
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/obd/socket/eunm/ObdDataType.kt
@@ -0,0 +1,19 @@
+package com.flightfeather.obd.socket.eunm
+
+import com.flightfeather.obd.socket.bean.*
+/**
+ * @author riku
+ * Date: 2019/9/15
+ * 瀹炴椂淇℃伅[RealTimeData]鍜岃ˉ鍙戜俊鎭痆ReplacementData]涓殑鏁版嵁绫诲瀷
+ * 绫诲瀷缂栫爜                     璇存槑
+ * 0x01                           OBD 淇℃伅
+ * 0x02                          鏁版嵁娴佷俊鎭�
+ * 0x03-0x7F                棰勭暀
+ * 0x80                          琛ュ厖鏁版嵁娴�
+ * 0x81~0xFE                鐢ㄦ埛鑷畾涔�
+ */
+enum class ObdDataType constructor(val value: Int){
+    ObdData(1),
+    EngineDataFlow(2),
+    SupplementDataFlow(128)
+}
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 2b6df51..00493e3 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -17,6 +17,7 @@
   not-empty: false
   identity: MYSQL
 
+#鏁版嵁搴撳垎椤甸厤缃�
 pagehelper:
     helperDialect: mysql
     reasonable: true
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..7353e5a
--- /dev/null
+++ b/src/main/resources/log4j2.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    6涓紭鍏堢骇浠庨珮鍒颁綆渚濇涓猴細OFF銆丗ATAL銆丒RROR銆乄ARN銆両NFO銆丏EBUG銆乀RACE銆� ALL銆�
+    濡傛灉璁剧疆浼樺厛绾т负WARN锛岄偅涔圤FF銆丗ATAL銆丒RROR銆乄ARN 4涓骇鍒殑log鑳芥甯歌緭鍑�
+    璁剧疆涓篛FF 琛ㄧず涓嶈褰昹og4j2鏈韩鐨勬棩蹇楋紝
+ -->
+
+<!-- status锛氱敤鏉ユ寚瀹歭og4j鏈韩鐨勬墦鍗版棩蹇楃骇鍒�,monitorInterval:鎸囧畾log4j鑷姩閲嶆柊閰嶇疆鐨勭洃娴嬮棿闅旀椂闂� -->
+<configuration status="INFO" monitorInterval="30">
+	<!-- 鑷繁璁剧疆灞炴�э紝鍚庨潰閫氳繃${}鏉ヨ闂� -->
+	<properties>
+		<property name="LOG_HOME">../obdLogs</property>
+	</properties>
+
+	<appenders>
+		<!--Appender 1. 杈撳嚭鍒癈onsole鎺у埗鍙帮紝鎸囧畾杈撳嚭鏍煎紡鍜岃繃婊ゅ櫒绛夌骇涓篒NFO -->
+		<Console name="Console" target="SYSTEM_OUT">
+			<!--ThresholdFilter鎸囧畾鏃ュ織娑堟伅鐨勮緭鍑烘渶浣庡眰娆�-->
+			<ThresholdFilter level="ALL" onMatch="ACCEPT" onMismatch="DENY"/>
+			<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
+		</Console>
+
+		<!--Appender 2. 杈撳嚭鍒版粴鍔ㄤ繚瀛樼殑鏂囦欢, 瑙﹀彂淇濆瓨鏃ュ織鏂囦欢鐨勬潯浠舵槸鏃ュ織鏂囦欢澶т簬3KB锛屽彧淇濆瓨鏈�鏂扮殑10涓棩蹇�-->
+		<File name="allLog" fileName="${LOG_HOME}/all.log">
+			<ThresholdFilter level="ALL" onMatch="ACCEPT" onMismatch="DENY"/>
+			<PatternLayout charset="UTF-8" pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
+		</File>
+
+
+		<!--Appender 3. 杈撳嚭鍒版粴鍔ㄤ繚瀛樼殑鏂囦欢, 瑙﹀彂淇濆瓨鏃ュ織鏂囦欢鐨勬潯浠舵槸鏃ュ織鏂囦欢澶т簬3KB锛屽彧淇濆瓨鏈�鏂扮殑10涓棩蹇�-->
+		<RollingFile name="debugLog" fileName="${LOG_HOME}/debug.log" filePattern="${LOG_HOME}/debug-%i.log">
+			<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
+			<PatternLayout charset="UTF-8" pattern="[%-5level][%d{yyyy-MM-dd HH:mm:ss}][%F:%L] - %m%n"/>
+			<SizeBasedTriggeringPolicy size="3KB"/>
+			<!-- DefaultRolloverStrategy 涓殑鍙傛暟max锛屽彲浠ラ檺鍒� SizeBasedTriggeringPolicy涓璼ize瓒呭嚭鍚庯紝鍙繚鐣檓ax涓瓨妗�-->
+			<DefaultRolloverStrategy max="10"/>
+		</RollingFile>
+
+		<!--Appender 4. 杈撳嚭鍒版粴鍔ㄤ繚瀛樼殑鏂囦欢, 瑙﹀彂淇濆瓨鏃ュ織鏂囦欢鐨勬潯浠舵槸姣忓垎閽熺涓�娆$殑鏃ュ織浜嬩欢銆侲RROR鏃ュ織鏄寜鍒嗛挓浜х敓鏃ュ織 -->
+		<RollingFile name="errorLog" fileName="${LOG_HOME}/error.log" filePattern="${LOG_HOME}/error-%d{yyyy-MM-dd_HH-mm}.log">
+			<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
+			<PatternLayout charset="UTF-8" pattern="[%-5level][%d{yyyy-MM-dd HH:mm:ss}][%C:%F:%L] - %m%n"/>
+			<TimeBasedTriggeringPolicy/>
+		</RollingFile>
+
+		<RollingFile name="RollingFile" fileName="${LOG_HOME}/rar.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{MM-dd-yyyy}-%i.log.gz">
+			<PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
+			<!--鏃ュ織鏂囦欢鏈�澶у�� 绗簩澶╁帇缂�-->
+			<Policies>
+				<TimeBasedTriggeringPolicy/>
+				<SizeBasedTriggeringPolicy size="10 MB"/>
+			</Policies>
+		</RollingFile>
+
+
+	</appenders>
+	<!--root 榛樿鍔犺浇-->
+	<loggers>
+		<root level="DEBUG">
+			<appender-ref ref="Console"/>
+			<!--<appender-ref ref="allLog"/>-->
+			<appender-ref ref="debugLog"/>
+			<appender-ref ref="errorLog"/>
+			<appender-ref ref="RollingFile"/>
+		</root>
+	</loggers>
+</configuration>
\ No newline at end of file
diff --git a/src/test/kotlin/com/flightfeather/obd/ObdApplicationTests.kt b/src/test/kotlin/com/flightfeather/obd/ObdApplicationTests.kt
index 93dea64..db1a9dc 100644
--- a/src/test/kotlin/com/flightfeather/obd/ObdApplicationTests.kt
+++ b/src/test/kotlin/com/flightfeather/obd/ObdApplicationTests.kt
@@ -6,6 +6,7 @@
 import com.google.gson.Gson
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.slf4j.LoggerFactory
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.test.context.SpringBootTest
 import org.springframework.test.context.junit4.SpringRunner
@@ -35,4 +36,14 @@
         println(map.cmdCode)
     }
 
+    @Test
+    fun logTest() {
+        val log = LoggerFactory.getLogger(javaClass)
+        log.trace("trace")
+        log.debug("debug")
+        log.warn("warn")
+        log.info("info")
+        log.error("error")
+    }
+
 }
diff --git a/src/test/kotlin/com/flightfeather/obd/Test.kt b/src/test/kotlin/com/flightfeather/obd/Test.kt
new file mode 100644
index 0000000..8b067b2
--- /dev/null
+++ b/src/test/kotlin/com/flightfeather/obd/Test.kt
@@ -0,0 +1,88 @@
+package com.flightfeather.obd
+
+import org.junit.Test
+import java.nio.charset.Charset
+import java.text.SimpleDateFormat
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2019/9/12
+ */
+class Test {
+
+    @Test
+    fun foo1() {
+        val b = ByteArray(20) {8}
+        println(b[18])
+    }
+
+    @Test
+    fun foo2() {
+        val b = ByteArray(1){97}
+        val s = "a"
+        println()
+    }
+
+    @Test
+    fun foo3() {
+        val hexNum = "ff"
+        val length = hexNum.toInt(16)
+        println(length)
+    }
+
+    @Test
+    fun foo4() {
+        val h = "0101"
+        val byte = 0xff
+        val b = h.toInt(16)
+        println(b)
+    }
+
+    @Test
+    fun foo5() {
+        val s = "23 23 30 30 30 30 30 35 33 31 36 30 38 30 31 30 35 33 36"
+        val sb = StringBuilder()
+        val ascii = s.split(" ")
+        ascii.forEach {
+            sb.append(it.toIntOrNull(16)?.toChar())
+        }
+        println(sb.toString())
+    }
+
+    @Test
+    fun foo6() {
+        val cal  = Calendar.getInstance().apply {
+            set(2019, 9, 15, 23, 16, 59)
+        }
+
+        println(SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cal.time))
+    }
+
+    @Test
+    fun foo7() {
+        val a = "0AAF".toIntOrNull(16)?.toString(2)
+        println(a)
+    }
+
+    @Test
+    fun foo8() {
+        val byte = ByteArray(2)
+        byte[0] = 0x23
+        byte[1] = 0x23
+
+        byte[0].toString(16)
+    }
+
+    @Test
+    fun foo9() {
+        val b = 128.toByte()
+        var a = 0
+        if (b < 0) {
+            a = b + 256
+        } else {
+            a = b.toInt()
+        }
+        println(b.toString(16))
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.3