dlt645.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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 dlt645 struct {
  170. name string
  171. }
  172. func bcd2int(bcd []byte) int64 {
  173. vi := int64(0)
  174. for i := 0; i < len(bcd); i++ {
  175. vi = (vi * 10) + int64((bcd[i]>>4)&0xF)
  176. vi = (vi * 10) + int64(bcd[i]&0xF)
  177. }
  178. return vi
  179. }
  180. func (p *dlt645) setDltAddr(buff []byte, amaddr string) error {
  181. addr, err := hex.DecodeString(amaddr)
  182. if err == nil {
  183. len := len(addr)
  184. for i := 0; i < len/2; i++ {
  185. j := len - i - 1
  186. addr[i], addr[j] = addr[j], addr[i]
  187. }
  188. copy(buff, addr)
  189. }
  190. return err
  191. }
  192. func (p *dlt645) setDltOpcode(buff []byte, opcode string) error {
  193. opc, err := hex.DecodeString(opcode)
  194. if err == nil {
  195. for i := 0; i < len(opc); i++ {
  196. buff[i+1] = opc[i] + 0x33
  197. }
  198. buff[0] = byte(len(opc))
  199. }
  200. return err
  201. }
  202. func (p *dlt645) setDltCheckSum(buff []byte) {
  203. sum := byte(0)
  204. pos := 0
  205. len := len(buff) - 1
  206. for ; pos < len && buff[pos] == 0xFE; pos++ {
  207. }
  208. for ; pos < len; pos++ {
  209. sum += buff[pos]
  210. }
  211. buff[len] = sum
  212. }
  213. func (p *dlt645) PackageCmd(opcode string, param ...interface{}) interface{} {
  214. amaddr := param[0].(string)
  215. buff := []byte{0xFE, 0xFE, 0xFE, 0xFE, DLT_CHAR_FRAME_START, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, DLT_CHAR_FRAME_START, DLT_DEF_CHAR_OPCODE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
  216. pkPos := DLT_LEAD_LEN + DLT_ADDR_POS
  217. err := p.setDltAddr(buff[pkPos:pkPos+DLT_ADDR_LEN], amaddr)
  218. if err != nil {
  219. log.Error("error in set meter addr ", amaddr)
  220. return nil
  221. }
  222. parampos := pkPos + DLT_ADDR_LEN + 2
  223. err = p.setDltOpcode(buff[parampos:parampos+5], opcode)
  224. if err != nil {
  225. log.Error("error in set op code ", opcode)
  226. return nil
  227. }
  228. p.setDltCheckSum(buff)
  229. buff = append(buff, 0x16)
  230. log.Infof("Send cmd [%s] to dtu[%s]\n", hex.EncodeToString(buff), amaddr)
  231. return buff
  232. }
  233. func Assert(est bool, infoi int) {
  234. if !est {
  235. _, file, line, ok := runtime.Caller(1)
  236. var serror string
  237. if ok {
  238. serror = fmt.Sprintf("Assert at [%s:%d]: (%d)", file, line, infoi)
  239. } else {
  240. serror = "parsecmd error with info:" + "" + strconv.Itoa(infoi)
  241. }
  242. panic(errors.New(serror))
  243. }
  244. }
  245. func (p *dlt645) skipLeader(buf []byte) (int, int) {
  246. pos := 0
  247. lenb := len(buf)
  248. for ; pos < lenb && (buf[pos] == 0xFF || buf[pos] == DLT_CHAR_HEADER); pos++ {
  249. }
  250. return pos, lenb
  251. }
  252. //fefefefe68040042050821681104333333332516
  253. //fefefefe6804004205082168910833333333b4bc34338016
  254. //fefefefe68 060042050821 68 91 08 33 33 33 33 47 c5 33 33 1d |16
  255. func (p *dlt645) ParsePacket(rxb []byte, params ...interface{}) (mapv interface{}) {
  256. if len(params) <= 0 || len(rxb) < 12 {
  257. return nil
  258. }
  259. defer func() {
  260. if err := recover(); err != nil {
  261. log.Infof("%s\n", err)
  262. }
  263. }()
  264. sum := byte(0)
  265. pos, lenb := p.skipLeader(rxb)
  266. Assert(rxb[pos] == DLT_CHAR_FRAME_START, int(rxb[pos]))
  267. for i := pos; i < lenb-2; i++ {
  268. sum += rxb[i]
  269. }
  270. Assert(rxb[lenb-1-1] == sum, int(sum))
  271. //get addr
  272. addr := rxb[pos+1 : pos+1+DLT_ADDR_LEN]
  273. for i := 0; i < DLT_ADDR_LEN/2; i++ {
  274. addr[i], addr[DLT_ADDR_LEN-i-1] = addr[DLT_ADDR_LEN-i-1], addr[i]
  275. }
  276. saddr := hex.EncodeToString(addr)
  277. if len(params) > 0 && reflect.TypeOf(params[0]).Kind() == reflect.Ptr {
  278. *params[0].(*string) = saddr
  279. }
  280. Assert(rxb[pos+DLT_FILED_POS] == DLT_CHAR_FRAME_START, int(rxb[pos+DLT_FILED_POS]))
  281. //CMD. opcode
  282. cmd := rxb[pos+DLT_OPCODE_POS]
  283. //PARAM = DIC_CODE + PARAM
  284. pos += DLT_DICCODE_POS
  285. lenParam := int(rxb[pos])
  286. pos++
  287. Assert(lenParam > DLT_DICCODE_LEN, lenParam)
  288. dicCode := 0
  289. dicBuff := bytes.NewBuffer(rxb[pos : pos+DLT_DICCODE_LEN])
  290. binary.Read(dicBuff, binary.LittleEndian, &dicCode)
  291. Assert(lenParam+pos < lenb-1, lenParam)
  292. param := make([]byte, lenParam)
  293. for i := 0; i < lenParam; i++ {
  294. param[lenParam-i-1] = rxb[pos+i] - 0x33
  295. }
  296. pos += lenParam
  297. Assert(rxb[pos+1] == DLT_CHAR_TAIL, int(rxb[pos+1]))
  298. if cmd == (C_2007_CODE_RD | DLT_CMD_DIR_REVERT) {
  299. val := float64(bcd2int(param[:lenParam-DLT_DICCODE_LEN])) / 100.0
  300. for k, v := range Cmd2Code {
  301. if int(v) == dicCode {
  302. mapv := make(map[string]interface{})
  303. mapv[k] = val
  304. return mapv
  305. }
  306. }
  307. } else if cmd == (C_2007_CODE_RDA | DLT_CMD_DIR_REVERT) {
  308. return saddr
  309. } else {
  310. log.Error("unkown DLT645 cmd:", cmd)
  311. }
  312. return nil
  313. }
  314. func (p *dlt645) VisableData(name string, opcode string, param interface{}) string {
  315. return ""
  316. }
  317. func (p *dlt645) Init(name string) error {
  318. p.name = name
  319. ProtList[p.name] = p
  320. return nil
  321. }
  322. func (p *dlt645) Uninit() {
  323. }
  324. func (p *dlt645) ChannelDispatch(rxb []byte) int {
  325. return 0
  326. }
  327. func NewDlt645() IProtocol {
  328. p := &dlt645{}
  329. p.Init("DLT645-2007")
  330. return p
  331. }
  332. var Cmd2Code map[string]uint32
  333. func init() {
  334. ProtReg["DLT645-2007"] = NewDlt645
  335. Cmd2Code = map[string]uint32{
  336. "TotalActivePower": DLT_GROUP_ACTIVE_POWER_TOTAL,
  337. }
  338. }