struct-layout.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. const {
  2. normalizeTypeText,
  3. parseDeclarator,
  4. parseFirstDeclarator,
  5. resolveType,
  6. splitDeclarations,
  7. splitDeclarators
  8. } = require('./struct-c-syntax.js')
  9. function isAsciiArray(typeText, dataType, name, arrayLength) {
  10. if (!arrayLength || arrayLength < 2 || arrayLength > 32) return false
  11. const normalizedType = normalizeTypeText(typeText).toLowerCase()
  12. if (normalizedType === 'char' || normalizedType === 'signed char') return true
  13. return dataType === 'uint8_t' && /(^|_)(model|name|text|str|string|chip|version|ver|serial|sn)($|_)/i.test(name)
  14. }
  15. function getDataTypeByteLength(dataType) {
  16. if (dataType === 'float' || dataType === 'int32_t' || dataType === 'uint32_t') return 4
  17. if (dataType === 'int8_t' || dataType === 'uint8_t') return 1
  18. return 2
  19. }
  20. function getBitFieldDataType(bitWidth) {
  21. const width = Math.max(1, Math.round(Number(bitWidth) || 1))
  22. if (width <= 8) return 'uint8_t'
  23. if (width <= 16) return 'uint16_t'
  24. return 'uint32_t'
  25. }
  26. function isBitType(typeText) {
  27. return normalizeTypeText(typeText).toLowerCase() === 'bit'
  28. }
  29. function alignLayoutToByte(layoutState) {
  30. if (layoutState.bitOffset % 8 !== 0) {
  31. layoutState.bitOffset += 8 - (layoutState.bitOffset % 8)
  32. }
  33. }
  34. function getLayoutByteStart(layoutState) {
  35. return Math.floor(layoutState.bitOffset / 8)
  36. }
  37. function advanceLayoutBytes(layoutState, byteLength) {
  38. layoutState.bitOffset += Math.max(1, Number(byteLength) || 1) * 8
  39. }
  40. function createBitFieldRegister(field, bitWidth, layoutState, name) {
  41. const width = Math.max(0, Math.round(Number(bitWidth) || 0))
  42. if (width === 0) {
  43. alignLayoutToByte(layoutState)
  44. return []
  45. }
  46. const byteStart = getLayoutByteStart(layoutState)
  47. const bitOffset = layoutState.bitOffset % 8
  48. layoutState.bitOffset += width
  49. if (!name) return []
  50. return [{
  51. bitOffset,
  52. bitWidth: width,
  53. byteStart,
  54. dataType: getBitFieldDataType(width),
  55. isBitField: true,
  56. name,
  57. unit: 'bit'
  58. }]
  59. }
  60. function createRegisterFromField(field, dataType, originalTypeText, layoutState) {
  61. const arrayLength = field.arrayDimensions.reduce((total, value) => total * value, 1)
  62. const hasArray = field.arrayDimensions.length > 0
  63. const bitFieldWidth = field.bitWidth !== null && field.bitWidth !== undefined
  64. ? field.bitWidth
  65. : (isBitType(originalTypeText) ? 1 : null)
  66. if (bitFieldWidth !== null && bitFieldWidth !== undefined) {
  67. if (hasArray) {
  68. const registers = []
  69. for (let index = 0; index < arrayLength; index += 1) {
  70. registers.push(...createBitFieldRegister(
  71. field,
  72. bitFieldWidth,
  73. layoutState,
  74. field.name ? `${field.name}[${index}]` : ''
  75. ))
  76. }
  77. return registers
  78. }
  79. return createBitFieldRegister(field, bitFieldWidth, layoutState, field.name)
  80. }
  81. alignLayoutToByte(layoutState)
  82. if (hasArray && isAsciiArray(originalTypeText, dataType, field.name, arrayLength)) {
  83. const byteStart = getLayoutByteStart(layoutState)
  84. advanceLayoutBytes(layoutState, arrayLength)
  85. return [{
  86. byteStart,
  87. dataType: 'ascii',
  88. name: field.name,
  89. textByteLength: String(arrayLength)
  90. }]
  91. }
  92. if (!hasArray) {
  93. const byteStart = getLayoutByteStart(layoutState)
  94. advanceLayoutBytes(layoutState, getDataTypeByteLength(dataType))
  95. return [{
  96. byteStart,
  97. dataType,
  98. name: field.name
  99. }]
  100. }
  101. const registers = []
  102. for (let index = 0; index < arrayLength; index += 1) {
  103. const byteStart = getLayoutByteStart(layoutState)
  104. advanceLayoutBytes(layoutState, getDataTypeByteLength(dataType))
  105. registers.push({
  106. byteStart,
  107. dataType,
  108. name: `${field.name}[${index}]`
  109. })
  110. }
  111. return registers
  112. }
  113. function parseStructFields(body, aliases) {
  114. const registers = []
  115. const layoutState = {
  116. bitOffset: 0
  117. }
  118. const declarations = splitDeclarations(body)
  119. declarations.forEach((statement) => {
  120. if (!statement || statement.indexOf('(') >= 0) return
  121. const parts = splitDeclarators(statement)
  122. if (!parts.length) return
  123. const first = parseFirstDeclarator(parts[0])
  124. if (!first) return
  125. const dataType = resolveType(first.typeText, aliases)
  126. if (!dataType) return
  127. const declarators = [first.declarator].concat(parts.slice(1))
  128. declarators.forEach((declaratorText) => {
  129. const field = parseDeclarator(declaratorText)
  130. if (!field) return
  131. registers.push(...createRegisterFromField(field, dataType, first.typeText, layoutState))
  132. })
  133. })
  134. return registers.map((register) => ({
  135. ...register,
  136. structByteLength: Math.ceil(layoutState.bitOffset / 8)
  137. }))
  138. }
  139. module.exports = {
  140. parseStructFields
  141. }