voltloggerParser.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package voltloggerParser
  2. import (
  3. "os"
  4. "io"
  5. "fmt"
  6. "strings"
  7. "encoding/binary"
  8. "devel.mephi.ru/dyokunev/voltlogger_parser/models"
  9. )
  10. const (
  11. WRITEBLOCK_SIZE int64 = 512
  12. WINDOW_SIZE int = 1 // Should be essentially less than 32768 (localTimestamp size/2)
  13. )
  14. type VoltloggerDumpRawHeader struct {
  15. Version byte
  16. Magic [11]byte
  17. Modificators byte // Bit: 1 — NoClock; 2 — Bitness8ADC; 4 — ZeroClockOnNewBlock; the rest is reserved
  18. ChannelsNum byte
  19. BlockWriteClockDelay byte
  20. Reserved0 [1]byte
  21. DeviceName [16]byte
  22. Reserved1 [480]byte
  23. }
  24. type VoltloggerDumpHeader struct {
  25. DeviceName [16]byte
  26. NoClock uint8
  27. Bitness8ADC uint8
  28. ZeroClockOnNewBlock uint8
  29. BlockWriteClockDelay int64
  30. ChannelsNum uint8
  31. }
  32. func makeWindow(r VoltloggerDumpHeader) (ret []models.VoltloggerRow) {
  33. ret = make([]models.VoltloggerRow, WINDOW_SIZE)
  34. /*
  35. for i:=0; i < WINDOW_SIZE; i++ {
  36. ret[i].Values = make([]int32, r.ChannelsNum)
  37. }
  38. */
  39. return ret
  40. }
  41. func pushPopWindow(window []models.VoltloggerRow, newRow models.VoltloggerRow) (oldRow models.VoltloggerRow) {
  42. oldestNum := 0
  43. for i:=0; i < WINDOW_SIZE; i++ {
  44. if (window[i].TimestampGlobal == 0) {
  45. window[i] = newRow
  46. continue
  47. }
  48. if (window[i].TimestampGlobal < window[oldestNum].TimestampGlobal) {
  49. oldestNum = i
  50. }
  51. }
  52. oldRow = window[oldestNum]
  53. window[oldestNum].TimestampGlobal = 0
  54. return oldRow
  55. }
  56. func get16(dumpFile *os.File) (r uint16, err error) {
  57. err = binary.Read(dumpFile, binary.LittleEndian, &r)
  58. return r, err
  59. }
  60. func get8(dumpFile *os.File) (r uint8, err error) {
  61. err = binary.Read(dumpFile, binary.LittleEndian, &r)
  62. return r, err
  63. }
  64. func ParseVoltloggerDump(dumpPath string, noHeaders bool, channelsNum uint8, adc8Bit bool, headerHandler func(VoltloggerDumpHeader, interface{})(error), rowHandler func(models.VoltloggerRow, VoltloggerDumpHeader, interface{})(error), arg interface{}) (err error) {
  65. var r VoltloggerDumpHeader
  66. // Openning the "dumpPath" as a file
  67. if (dumpPath == "-") {
  68. dumpPath = "/dev/stdin"
  69. }
  70. dumpFile, err := os.Open(dumpPath)
  71. if (err != nil) {
  72. return err
  73. }
  74. defer dumpFile.Close()
  75. if (noHeaders) {
  76. r.ChannelsNum = 1
  77. r.NoClock = 0
  78. } else {
  79. // Reading binary header to a VoltloggerDumpRawHeader
  80. var raw VoltloggerDumpRawHeader
  81. err = binary.Read(dumpFile, binary.LittleEndian, &raw)
  82. if (err != nil) {
  83. return fmt.Errorf("Cannot read dump: %v", err.Error())
  84. }
  85. // Checking if the data of a known type
  86. magicString := string(raw.Magic[:])
  87. if (magicString != "voltlogger\000") {
  88. return fmt.Errorf("The source is not a voltlogger dump (magic doesn't match: \"%v\" != \"voltlogger\")", magicString)
  89. }
  90. if (raw.Version != 0) {
  91. return fmt.Errorf("Unsupported dump version: %v", raw.Version)
  92. }
  93. if ((raw.Modificators & (0xff ^ 0x07)) != 0) {
  94. return fmt.Errorf("Unsupported modificators bitmask: %o %o", raw.Modificators)
  95. }
  96. if (raw.ChannelsNum == 0) {
  97. return fmt.Errorf("Channels number is zero")
  98. }
  99. // Filling the VoltloggerDump struct
  100. DeviceName := strings.Trim(string(raw.DeviceName[:]), "\000")
  101. copy(r.DeviceName[:], DeviceName)
  102. r.NoClock = raw.Modificators & 0x01
  103. r.Bitness8ADC = raw.Modificators & 0x02
  104. r.ZeroClockOnNewBlock = raw.Modificators & 0x04
  105. r.BlockWriteClockDelay = int64(raw.BlockWriteClockDelay)
  106. err = headerHandler(r, arg);
  107. if (err != nil) {
  108. return fmt.Errorf("Got an error from headerHandler: %v", err);
  109. }
  110. r.ChannelsNum = uint8(raw.ChannelsNum)
  111. }
  112. if (channelsNum > 0) {
  113. r.ChannelsNum = channelsNum
  114. }
  115. if (adc8Bit) {
  116. r.Bitness8ADC = 1;
  117. }
  118. // Parsing the Data
  119. var pos int64
  120. var timestampLocalOld uint16
  121. var row models.VoltloggerRow
  122. row.TimestampGlobal = -1
  123. window := makeWindow(r)
  124. for err = nil; err == nil; pos++ {
  125. row.TimestampLocal = 0;
  126. if (r.NoClock != 0) {
  127. row.TimestampGlobal++
  128. } else {
  129. row.TimestampLocal, err = get16(dumpFile)
  130. if (err != nil) {
  131. break
  132. }
  133. if (row.TimestampGlobal < 0) {
  134. row.TimestampGlobal = int64(row.TimestampLocal)
  135. } else {
  136. var timestampLocalDiff int
  137. timestampLocalDiff = int(row.TimestampLocal) - int(timestampLocalOld)
  138. /*if (timestampLocalDiff*timestampLocalDiff > TIMESTAMP_WINDOW*TIMESTAMP_WINDOW) {
  139. break
  140. }*/
  141. timestampLocalOld = uint16(row.TimestampLocal)
  142. if (timestampLocalDiff < 0) {
  143. if (r.ZeroClockOnNewBlock != 0) {
  144. timestampLocalDiff = 0
  145. } else {
  146. timestampLocalDiff += (1 << 16)
  147. }
  148. row.TimestampGlobal += r.BlockWriteClockDelay
  149. }
  150. row.TimestampGlobal += int64(timestampLocalDiff)
  151. }
  152. }
  153. row.Values = make([]int32, r.ChannelsNum)
  154. for i:=uint8(0); i < r.ChannelsNum; i++ {
  155. var value uint16
  156. if (r.Bitness8ADC != 0) {
  157. var value8 uint8
  158. value8, err = get8(dumpFile)
  159. value = uint16(value8)
  160. } else {
  161. value, err = get16(dumpFile)
  162. }
  163. if (err != nil) {
  164. break
  165. }
  166. row.Values[i] = int32(value)
  167. }
  168. row = pushPopWindow(window, row)
  169. if (row.TimestampGlobal == 0) { // If the window is not filled, yet
  170. continue
  171. }
  172. timestampLocalOld = row.TimestampLocal
  173. err = rowHandler(row, r, arg);
  174. if (err != nil) {
  175. return fmt.Errorf("Got an error from rowHandler: %v", err);
  176. }
  177. }
  178. if (err == io.EOF) {
  179. err = nil
  180. }
  181. return err
  182. }