dlt645.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. package protocol
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/hex"
  6. "errors"
  7. "fmt"
  8. "reflect"
  9. "runtime"
  10. "strconv"
  11. "github.com/yuguorong/go/log"
  12. )
  13. /*
  14. "9521003872": {"2108", "05420005", "05420003", "05420002"}, //6f
  15. "9521003712": {"2108", "05420001"}, //1F
  16. "9521003534": {"2108", "05420006"}, //-1F
  17. "9521003697": {"2108", "05420004"}, //5c
  18. //fefefefe68040042050821681104333333332516
  19. //fefefefe68 04 00 42 05 08 21 68910833333333b4bc34338016
  20. data [{"accessToken":"AZM7QSPRqsV4CUxIGldn",
  21. "id":"1ec23004b88a020bf52b38d8579115b",
  22. "mqttServer":"test-sbuilding.pacom.cn:1885",
  23. "name":"FGGW10-202110020001"}]
  24. reqParam {"gwDevId":"1ec23004b88a020bf52b38d8579115b","pageNum":1,"pageSize":100} https://test-admin.pacom.cn/platform/dev/get-ammeter-list 2021-10-03 23:10:26.175516015 +0800 CST m=+7.127250782
  25. data [
  26. {"address":"05420005",
  27. "code":"2108",
  28. "devName":"AM10-9521003872210805",
  29. "dutSn":"9521003872",
  30. "gwDevId":"1ec23004b88a020bf52b38d8579115b",
  31. "id":"1ec2300601517d0bf52b38d8579115b",
  32. "protocol":"DLT645-2007"},
  33. {"address":"05420001","code":"2108","devName":"AM10-9521003712210805","dutSn":"9521003712","gwDevId":"1ec23004b88a020bf52b38d8579115b","id":"1ec230092bb8de0bf52b38d8579115b","protocol":"DLT645-2007"},{"address":"05420006","code":"2108","devName":"AM10-9521003534210805","dutSn":"9521003534","gwDevId":"1ec23004b88a020bf52b38d8579115b","id":"1ec23009ed76090bf52b38d8579115b","protocol":"DLT645-2007"},{"address":"05420004","code":"2108","devName":"AM10-9521003697210805","dutSn":"9521003697","gwDevId":"1ec23004b88a020bf52b38d8579115b","id":"1ec2300abbc2890bf52b38d8579115b","protocol":"DLT645-2007"}]
  34. FE FE FE FE
  35. 0 68H 帧起始符
  36. 1 A0 地址域
  37. 2 A1
  38. 3 A2
  39. 4 A3
  40. 5 A4
  41. 6 A5
  42. 7 68H 帧起始符
  43. 8 C 控制码
  44. 9 L 数据域长度
  45. 10 DATA 数据域
  46. 11 CS 校验码
  47. */
  48. const (
  49. C_CODE_MASK = 0x1F //功能码标志位
  50. //功能码
  51. C_2007_CODE_BRC = 0x08 //广播校时
  52. C_2007_CODE_RD = 0x11 //读数据
  53. C_2007_CODE_RDM = 0x12 //读后续数据
  54. C_2007_CODE_RDA = 0x13 //读通信地址
  55. C_2007_CODE_WR = 0x14 //写数据
  56. C_2007_CODE_WRA = 0x15 //写通信地址
  57. C_2007_CODE_DJ = 0x16 //冻结
  58. C_2007_CODE_BR = 0x17 //更改通信速率
  59. C_2007_CODE_PD = 0x18 //修改密码
  60. C_2007_CODE_XL = 0x19 //最大需量清零
  61. C_2007_CODE_DB = 0x1a //电表清零
  62. C_2007_CODE_MSG = 0x1b //事件清零
  63. ERR_2007_RATE = 0x40 //费率数超
  64. ERR_2007_DAY = 0x20 //日时段数超
  65. ERR_2007_YEAR = 0x10 //年时区数超
  66. ERR_2007_BR = 0x08 //通信速率不能更改
  67. ERR_2007_PD = 0x04 //密码错误/未授权
  68. ERR_2007_DATA = 0x02 //无请求数据
  69. ERR_2007_OTHER = 0x01 //其他错误
  70. /*DLT 645 2007数据标识*/
  71. DLT_GROUP_ACTIVE_POWER_TOTAL = 0x0 //组合有功总电能
  72. DLT_PRIC1_GROUP_ACTIVE_POWER_TOTAL = 0x100 //组合有功费率1电能
  73. DLT_PRIC2_GROUP_ACTIVE_POWER_TOTAL = 0x200 //组合有功费率2电能
  74. DLT_PRIC3_GROUP_ACTIVE_POWER_TOTAL = 0x300 //组合有功费率3电能
  75. DLT_PRIC4_GROUP_ACTIVE_POWER_TOTAL = 0x400 //组合有功费率4电能
  76. DLT_GROUP_FORTH_POWER_TOTAL = 0x10000 //正向有功总电能
  77. DLT_PRIC1_GROUP_FORTH_POWER_TOTAL = 0x10100 //正向有功费率1电能
  78. DLT_PRIC2_GROUP_FORTH_POWER_TOTAL = 0x10200 //正向有功费率2电能
  79. DLT_PRIC3_GROUP_FORTH_POWER_TOTAL = 0x10300 //正向有功费率3电能
  80. DLT_PRIC4_GROUP_FORTH_POWER_TOTAL = 0x10400 //正向有功费率4电能
  81. DLT_GROUP_BACK_POWER_TOTAL = 0x20000 //反向有功总电能
  82. DLT_PRIC1_GROUP_BACK_POWER_TOTAL = 0x20100 //反向有功费率1电能
  83. DLT_PRIC2_GROUP_BACK_POWER_TOTAL = 0x20200 //反向有功费率2电能
  84. DLT_PRIC3_GROUP_BACK_POWER_TOTAL = 0x20300 //反向有功费率3电能
  85. DLT_PRIC4_GROUP_BACK_POWER_TOTAL = 0x20400 //反向有功费率4电能
  86. DLT_GROUP_NONE1_POWER_TOTAL = 0x30000 //组合无功1总电能
  87. DLT_GROUP_NONE2_POWER_TOTAL = 0x40000 //组合无功2总电能
  88. DLT_GROUP_QUAD1_NONE_POWER_TOTAL = 0x50000 //第一象限无功电能
  89. DLT_GROUP_QUAD2_NONE_POWER_TOTAL = 0x60000 //第二象限无功电能
  90. DLT_GROUP_QUAD3_NONE_POWER_TOTAL = 0x70000 //第三象限无功电能
  91. DLT_GROUP_QUAD4_NONE_POWER_TOTAL = 0x80000 //第四象限无功电能
  92. DLT_GROUP_FORTH_APPARENT_POWER_TOTAL = 0x90000 //正向视在总电能
  93. DLT_PHASE_A_VOLTAGE = 0x2010100 //A相电压
  94. DLT_PHASE_B_VOLTAGE = 0x2010200 //B相电压
  95. DLT_PHASE_C_VOLTAGE = 0x2010300 //C相电压
  96. DLT_PHASE_A_CURENT = 0x2020100 //A相电流
  97. DLT_PHASE_B_CURENT = 0x2020200 //B相电流
  98. DLT_PHASE_C_CURENT = 0x2020300 //C相电流
  99. DIC_2030000 = 0x2030000 //总有功功率
  100. DIC_2030100 = 0x2030100 //A相有功功率
  101. DIC_2030200 = 0x2030200 //B相有功功率
  102. DIC_2030300 = 0x2030300 //C相有功功率
  103. DIC_2040000 = 0x2040000 //总无功功率
  104. DIC_2040100 = 0x2040100 //A相无功功率
  105. DIC_2040200 = 0x2040200 //B相无功功率
  106. DIC_2040300 = 0x2040300 //C相无功功率
  107. DIC_2050000 = 0x2050000 //总视在功率
  108. DIC_2050100 = 0x2050100 //A相视在功率
  109. DIC_2050200 = 0x2050200 //B相视在功率
  110. DIC_2050300 = 0x2050300 //C相视在功率
  111. DIC_2060000 = 0x2060000 //总功率因素
  112. DIC_2060100 = 0x2060100 //A相功率因素
  113. DIC_2060200 = 0x2060200 //B相功率因素
  114. DIC_2060300 = 0x2060300 //C相功率因素
  115. DIC_20C0100 = 0x20C0100 //AB线电压
  116. DIC_20C0200 = 0x20C0200 //BC线电压
  117. DIC_20C0300 = 0x20C0300 //CA线电压
  118. DIC_2800002 = 0x2800002 //频率
  119. DIC_4000101 = 0x4000101 //年月日星期
  120. DIC_4000102 = 0x4000102 //时分秒
  121. DIC_5060001 = 0x5060001 //上一次日冻结时间
  122. DIC_5060101 = 0x5060101 //上一次日冻结正向有功电能
  123. DIC_30C0000 = 0x30C0000 //过流总次数,总时间
  124. DIC_30C0101 = 0x30C0101 //上一次A相过流记录
  125. DIC_3300100 = 0x3300100 //电表清零总次数
  126. DIC_3300101 = 0x3300101 //电表清零记录
  127. DIC_4000501 = 0x4000501
  128. DIC_4000502 = 0x4000502
  129. DIC_4000503 = 0x4000503
  130. DIC_4000504 = 0x4000504
  131. DIC_4000505 = 0x4000505
  132. DIC_4000506 = 0x4000506
  133. DIC_4000507 = 0x4000507
  134. DIC_4000403 = 0x4000403 //资产管理编码
  135. DIC_4000701 = 0x4000701 //信号强度
  136. DIC_4000702 = 0x4000702 //版本号
  137. DIC_7000001 = 0x7000001 //master_api_key
  138. DIC_7000002 = 0x7000002 //device_id
  139. )
  140. const (
  141. DLT_CHAR_HEADER = 0xFE
  142. DLT_CHAR_TAIL = 0x16
  143. DLT_CHAR_FRAME_START = 0x68
  144. DLT_DEF_CHAR_OPCODE = C_2007_CODE_RD
  145. DLT_ADDR_POS = 1
  146. DLT_FILED_POS = 7
  147. DLT_OPCODE_POS = 8
  148. DLT_DICCODE_POS = 9
  149. DLT_DICCODE_LEN = 4
  150. DLT_PARAM_POS = 9
  151. DLT_ADDR_LEN = 6
  152. DLT_LEAD_LEN = 4
  153. DLT_CMD_DIR_REVERT = 0x80
  154. )
  155. /*FE FE FE FE
  156. 0 68H 帧起始符
  157. 1 A0 地址域
  158. 2 A1
  159. 3 A2
  160. 4 A3
  161. 5 A4
  162. 6 A5
  163. 7 68H 帧起始符
  164. 8 C 控制码
  165. 9 L 数据域长度
  166. 10 DATA 数据域
  167. 11 CS 校验码
  168. */
  169. type dlt645Opcode struct {
  170. ctrl int32
  171. dataID int32
  172. dIDLen int32
  173. }
  174. type dlt645 struct {
  175. name string
  176. }
  177. const (
  178. DEFAULT_OPCODE = "TotalActivePower"
  179. )
  180. func bcd2int(bcd []byte) int64 {
  181. vi := int64(0)
  182. for i := 0; i < len(bcd); i++ {
  183. vi = (vi * 10) + int64((bcd[i]>>4)&0xF)
  184. vi = (vi * 10) + int64(bcd[i]&0xF)
  185. }
  186. return vi
  187. }
  188. func (p *dlt645) setDltAddr(buff []byte, amaddr string) error {
  189. addr, err := hex.DecodeString(amaddr)
  190. if err == nil {
  191. len := len(addr)
  192. for i := 0; i < len/2; i++ {
  193. j := len - i - 1
  194. addr[i], addr[j] = addr[j], addr[i]
  195. }
  196. copy(buff, addr)
  197. }
  198. return err
  199. }
  200. func (p *dlt645) setDltOpcode(buff []byte, opcode string) error {
  201. opc, err := hex.DecodeString(opcode)
  202. if err == nil {
  203. for i := 0; i < len(opc); i++ {
  204. buff[i+1] = opc[i] + 0x33
  205. }
  206. buff[0] = byte(len(opc))
  207. }
  208. return err
  209. }
  210. func (p *dlt645) setDltCheckSum(buff []byte) {
  211. sum := byte(0)
  212. pos := 0
  213. len := len(buff) - 1
  214. for ; pos < len && buff[pos] == 0xFE; pos++ {
  215. }
  216. for ; pos < len; pos++ {
  217. sum += buff[pos]
  218. }
  219. buff[len] = sum
  220. }
  221. func (p *dlt645) PackageCmd(strcmd string, param ...interface{}) interface{} {
  222. opcode, has := cmd2DataField[strcmd]
  223. if !has {
  224. return nil
  225. }
  226. amaddr := "BROADCAST"
  227. buff := []byte{0xFE, 0xFE, 0xFE, 0xFE, DLT_CHAR_FRAME_START, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
  228. DLT_CHAR_FRAME_START, byte(opcode.ctrl), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, DLT_CHAR_TAIL}
  229. pkPos := DLT_LEAD_LEN + DLT_ADDR_POS
  230. if len(param) > 0 {
  231. amaddr = param[0].(string)
  232. err := p.setDltAddr(buff[pkPos:pkPos+DLT_ADDR_LEN], amaddr)
  233. if err != nil {
  234. log.Error("error in set meter addr ", amaddr)
  235. return nil
  236. }
  237. }
  238. parampos := pkPos + DLT_ADDR_LEN + 2
  239. if opcode.dIDLen > 0 {
  240. sDataID := fmt.Sprintf("%08d", int(opcode.dataID))
  241. if err := p.setDltOpcode(buff[parampos:parampos+int(opcode.dIDLen)+1], sDataID); err != nil {
  242. log.Error("error in set op code ", opcode)
  243. return nil
  244. }
  245. parampos += int(opcode.dIDLen) + 1
  246. } else {
  247. buff[parampos] = 0
  248. parampos++
  249. }
  250. p.setDltCheckSum(buff[:parampos+1])
  251. buff[parampos+1] = DLT_CHAR_TAIL
  252. //[fefefefe68020068361211681104333333337416] to dtu[111236680002]
  253. log.Infof("Pack cmd [%s] to dtu[%s]\n", hex.EncodeToString(buff), amaddr) //
  254. return buff[:parampos+2]
  255. }
  256. func Assert(est bool, infoi int) {
  257. if !est {
  258. _, file, line, ok := runtime.Caller(1)
  259. var serror string
  260. if ok {
  261. serror = fmt.Sprintf("Assert at [%s:%d]: (%d)", file, line, infoi)
  262. } else {
  263. serror = "parsecmd error with info:" + "" + strconv.Itoa(infoi)
  264. }
  265. panic(errors.New(serror))
  266. }
  267. }
  268. func (p *dlt645) skipLeader(buf []byte) (int, int) {
  269. pos := 0
  270. lenb := len(buf)
  271. for ; pos < lenb && (buf[pos] == 0xFF || buf[pos] == DLT_CHAR_HEADER); pos++ {
  272. }
  273. return pos, lenb
  274. }
  275. //fefefefe68040042050821681104333333332516
  276. //fefefefe6804004205082168910833333333b4bc34338016
  277. //fefefefe68 060042050821 68 91 08 33 33 33 33 47 c5 33 33 1d |16
  278. func (p *dlt645) ParsePacket(rxb []byte, params ...interface{}) (mapv interface{}) {
  279. if len(params) <= 0 || len(rxb) < 12 {
  280. return nil
  281. }
  282. defer func() {
  283. if err := recover(); err != nil {
  284. log.Infof("%s\n", err)
  285. }
  286. }()
  287. sum := byte(0)
  288. pos, lenb := p.skipLeader(rxb)
  289. Assert(rxb[pos] == DLT_CHAR_FRAME_START, int(rxb[pos]))
  290. for i := pos; i < lenb-2; i++ {
  291. sum += rxb[i]
  292. }
  293. Assert(rxb[lenb-1-1] == sum, int(sum))
  294. //get addr
  295. addr := make([]uint8, DLT_ADDR_LEN) // rxb[pos+1 : pos+1+DLT_ADDR_LEN]
  296. for i := 0; i < DLT_ADDR_LEN; i++ {
  297. addr[i] = rxb[pos+DLT_ADDR_LEN-i] //, addr[DLT_ADDR_LEN-i-1] = addr[DLT_ADDR_LEN-i-1], addr[i]
  298. }
  299. saddr := hex.EncodeToString(addr) //"111236680002"
  300. if len(params) > 0 && reflect.TypeOf(params[0]).Kind() == reflect.Ptr {
  301. *params[0].(*string) = saddr
  302. }
  303. Assert(rxb[pos+DLT_FILED_POS] == DLT_CHAR_FRAME_START, int(rxb[pos+DLT_FILED_POS]))
  304. //CMD. opcode
  305. cmd := rxb[pos+DLT_OPCODE_POS]
  306. //PARAM = DIC_CODE + PARAM
  307. pos += DLT_DICCODE_POS
  308. lenParam := int(rxb[pos])
  309. pos++
  310. Assert(lenParam > DLT_DICCODE_LEN, lenParam)
  311. dicCode := 0
  312. dicBuff := bytes.NewBuffer(rxb[pos : pos+DLT_DICCODE_LEN])
  313. binary.Read(dicBuff, binary.LittleEndian, &dicCode)
  314. Assert(lenParam+pos < lenb-1, lenParam)
  315. param := make([]byte, lenParam)
  316. for i := 0; i < lenParam; i++ {
  317. param[lenParam-i-1] = rxb[pos+i] - 0x33
  318. }
  319. pos += lenParam
  320. Assert(rxb[pos+1] == DLT_CHAR_TAIL, int(rxb[pos+1]))
  321. if cmd == (C_2007_CODE_RD | DLT_CMD_DIR_REVERT) {
  322. val := float64(bcd2int(param[:lenParam-DLT_DICCODE_LEN])) / 100.0
  323. for k, v := range cmd2DataField {
  324. if (byte(v.ctrl) | DLT_CMD_DIR_REVERT) == cmd {
  325. mapv := make(map[string]interface{})
  326. mapv[k] = val
  327. return mapv
  328. }
  329. }
  330. } else if cmd == (C_2007_CODE_RDA | DLT_CMD_DIR_REVERT) {
  331. return saddr
  332. } else {
  333. log.Error("unkown DLT645 cmd:", cmd)
  334. }
  335. return nil
  336. }
  337. func (p *dlt645) VisableData(name string, opcode string, param interface{}) string {
  338. return ""
  339. }
  340. func (p *dlt645) Init(name string) error {
  341. p.name = name
  342. ProtList[p.name] = p
  343. return nil
  344. }
  345. func (p *dlt645) Uninit() {
  346. }
  347. func (p *dlt645) ChannelDispatch(rxb []byte) int {
  348. return 0
  349. }
  350. func NewDlt645() IProtocol {
  351. p := &dlt645{}
  352. p.Init("DLT645-2007")
  353. return p
  354. }
  355. var cmd2DataField map[string]dlt645Opcode
  356. func init() {
  357. ProtReg["DLT645-2007"] = NewDlt645
  358. cmd2DataField = map[string]dlt645Opcode{
  359. "TotalActivePower": {C_2007_CODE_RD, DLT_GROUP_ACTIVE_POWER_TOTAL, 4},
  360. "ReadAddress": {C_2007_CODE_RDA, 0, 0},
  361. }
  362. }