a Go library for reading iridium short data bursts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
3.7 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. package sdb
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "time"
  7. )
  8. type IridiumSDB struct {
  9. ProtocolRevision byte
  10. Length uint16
  11. Elements []interface{}
  12. }
  13. type MOHeader struct {
  14. IEI byte
  15. Length uint16
  16. CDRReference uint32
  17. IMEI [15]byte
  18. Status byte
  19. MOMSN uint16
  20. MTMSN uint16
  21. TimeSession uint32
  22. }
  23. func (h MOHeader) SessionTime() time.Time {
  24. return time.Unix(int64(h.TimeSession), 0)
  25. }
  26. func (h MOHeader) StatusString() string {
  27. switch h.Status {
  28. case 0:
  29. return "The SBD session completed successfully."
  30. case 1:
  31. return "The MO message transfer, if any, was successful. The MT message queued at the Iridium Gateway is too large to be transferred within a single SBD session."
  32. case 2:
  33. return "The MO message transfer, if any, was successful. The reported location was determined to be of unacceptable quality. This value is only applicable to IMEIs using SBD protocol revision 1."
  34. case 10:
  35. return "The SBD session timed out before session completion."
  36. case 12:
  37. return "The MO message being transferred by the IMEI is too large to be transferred within a single SBD session."
  38. case 13:
  39. return "An RF link loss occurred during the SBD session."
  40. case 14:
  41. return "An IMEI protocol anomaly occurred during SBD session."
  42. case 15:
  43. return "The IMEI is prohibited from accessing the Iridium Gateway."
  44. default:
  45. return ""
  46. }
  47. }
  48. type MOPayload struct {
  49. IEI byte
  50. Length uint16
  51. Payload []byte
  52. }
  53. type MOLocation struct {
  54. IEI byte
  55. Length uint16
  56. LocationFlags byte
  57. LatitudeDegrees uint8
  58. LatitudeTHMinute uint16
  59. LongitudeDegrees uint8
  60. LongitudeTHMinute uint16
  61. CEPRadius uint32
  62. }
  63. type MOConfirmation struct {
  64. IEI byte
  65. Length uint16
  66. Status byte
  67. }
  68. func ParseSDB(raw []byte) (*IridiumSDB, error) {
  69. raw_len := len(raw)
  70. if raw_len < 3 {
  71. return nil, fmt.Errorf("message structure too short: %d bytes",
  72. len(raw))
  73. }
  74. sdb := IridiumSDB{}
  75. sdb.ProtocolRevision = raw[0]
  76. sdb.Length = binary.BigEndian.Uint16(raw[1:3])
  77. if (int(sdb.Length) + 3) != raw_len {
  78. return nil, fmt.Errorf("invalid message length (expected %d, got %d)",
  79. (sdb.Length + 3), raw_len)
  80. }
  81. for i := 3; i < raw_len; {
  82. if (i + 3) > raw_len {
  83. return nil, fmt.Errorf("invalid element length (at %d)",
  84. i)
  85. }
  86. el_iei := raw[i]
  87. el_len := binary.BigEndian.Uint16(raw[i+1 : i+3])
  88. if (i + 3 + int(el_len)) > raw_len {
  89. return nil, fmt.Errorf("invalid element length (at %d): %d",
  90. i+1, el_len)
  91. }
  92. switch el_iei {
  93. // MO Header IEI
  94. case 1:
  95. buf := bytes.NewReader(raw[i : i+3+int(el_len)])
  96. moheader := MOHeader{}
  97. err := binary.Read(buf, binary.BigEndian, &moheader)
  98. if err != nil {
  99. return nil, fmt.Errorf("error reading MO header (at %d): %s",
  100. i, err.Error())
  101. }
  102. sdb.Elements = append(sdb.Elements, moheader)
  103. // MO Payload IEI
  104. case 2:
  105. mopayload := MOPayload{}
  106. mopayload.IEI = el_iei
  107. mopayload.Length = el_len
  108. mopayload.Payload = raw[i+3 : i+3+int(el_len)]
  109. sdb.Elements = append(sdb.Elements, mopayload)
  110. // MO Location IEI
  111. case 3:
  112. buf := bytes.NewReader(raw[i : i+3+int(el_len)])
  113. molocation := MOLocation{}
  114. err := binary.Read(buf, binary.BigEndian, &molocation)
  115. if err != nil {
  116. return nil, fmt.Errorf("error reading MO location (at %d): %s",
  117. i, err.Error())
  118. }
  119. sdb.Elements = append(sdb.Elements, molocation)
  120. // MO Confirmation IEI
  121. case 5:
  122. moconfirmation := MOConfirmation{}
  123. moconfirmation.IEI = el_iei
  124. moconfirmation.Length = el_len
  125. moconfirmation.Status = raw[i+3]
  126. sdb.Elements = append(sdb.Elements, moconfirmation)
  127. default:
  128. return nil, fmt.Errorf("invalid element IEI (at %d): %d",
  129. i, el_iei)
  130. }
  131. i += (3 + int(el_len))
  132. }
  133. return &sdb, nil
  134. }