struct-completion.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. const {
  2. getDataType,
  3. normalizeGroup
  4. } = require('../../domain/parameter-groups/model.js')
  5. const {
  6. parseStructCatalog,
  7. parseStructDefinition: parseStructDefinitionSource
  8. } = require('../../domain/parameter-groups/struct-parser.js')
  9. function getRegisterByteLengthFromConfig(register) {
  10. const dataType = getDataType(register.dataType).key
  11. if (dataType === 'ascii' || dataType === 'utf8') return Math.max(1, Number(register.textByteLength) || 1)
  12. if (dataType === 'float' || dataType === 'int32_t' || dataType === 'uint32_t') return 4
  13. if (dataType === 'int8_t' || dataType === 'uint8_t') return 1
  14. return 2
  15. }
  16. function getRegistersByteLength(registers = []) {
  17. const explicitByteEnds = registers.map((register) => {
  18. const byteStart = Number(register && register.byteStart)
  19. if (!Number.isFinite(byteStart)) return null
  20. if (register.isBitField) {
  21. const bitOffset = Math.min(Math.max(Math.floor(Number(register.bitOffset) || 0), 0), 7)
  22. const bitWidth = Math.max(1, Math.round(Number(register.bitWidth) || 1))
  23. return Math.max(0, Math.floor(byteStart)) + Math.max(1, Math.ceil((bitOffset + bitWidth) / 8))
  24. }
  25. return Math.max(0, Math.floor(byteStart)) + getRegisterByteLengthFromConfig(register)
  26. }).filter((value) => Number.isFinite(value))
  27. if (explicitByteEnds.length) return Math.max.apply(null, explicitByteEnds)
  28. return registers.reduce((total, register) => total + getRegisterByteLengthFromConfig(register), 0)
  29. }
  30. function normalizeSymbolText(value) {
  31. return String(value || '')
  32. .replace(/^(?:IDATA|XDATA|DATA|CODE)[\s:_-]+/i, '')
  33. .replace(/^_+/, '')
  34. .replace(/[^A-Za-z0-9]/g, '')
  35. .toLowerCase()
  36. }
  37. function findStructCompletion(group, catalog) {
  38. const symbolName = group.sourceSymbolName || group.name
  39. const direct = catalog.variablesByName[normalizeSymbolText(symbolName)]
  40. || catalog.variablesByName[symbolName]
  41. if (direct) return direct
  42. const normalizedSymbol = normalizeSymbolText(symbolName)
  43. const normalizedType = normalizeSymbolText(group.sourceSymbolType)
  44. const expectedBytes = Number(group.sourceByteLength || group.byteLength || 0)
  45. const matchedStruct = catalog.structs.find((structInfo) => {
  46. const normalizedStructName = normalizeSymbolText(structInfo.name)
  47. if (normalizedType && normalizedType === normalizedStructName) {
  48. return true
  49. }
  50. if (normalizedSymbol && (
  51. normalizedSymbol === normalizedStructName
  52. || normalizedSymbol.indexOf(normalizedStructName) >= 0
  53. || normalizedStructName.indexOf(normalizedSymbol) >= 0
  54. )) {
  55. return true
  56. }
  57. return expectedBytes > 0 && getRegistersByteLength(structInfo.registers) === expectedBytes
  58. })
  59. return matchedStruct
  60. ? {
  61. name: symbolName,
  62. registers: matchedStruct.registers,
  63. structName: matchedStruct.name
  64. }
  65. : null
  66. }
  67. function createCompletedRegisters(group, completion) {
  68. const existingRemarksByByteStart = (Array.isArray(group.registers) ? group.registers : []).reduce((remarks, register) => {
  69. const byteStart = Number(register && register.byteStart)
  70. const remark = String(register && register.remark ? register.remark : '').trim()
  71. if (Number.isFinite(byteStart) && remark) remarks[Math.floor(byteStart)] = remark
  72. return remarks
  73. }, {})
  74. return completion.registers.map((register) => ({
  75. ...register,
  76. isStructField: true,
  77. remark: register.remark || existingRemarksByByteStart[Math.floor(Number(register.byteStart) || 0)] || '',
  78. sourceMemoryArea: group.sourceMemoryArea,
  79. sourceMemoryClass: group.sourceMemoryClass,
  80. sourceSymbolName: group.sourceSymbolName,
  81. sourceSymbolType: completion.structName || register.sourceSymbolType
  82. }))
  83. }
  84. function completeStructInstanceGroups(groups, sourceText, options = {}) {
  85. const catalog = parseStructCatalog(sourceText)
  86. let completedCount = 0
  87. let skippedCount = 0
  88. const nextGroups = groups.map((group) => {
  89. if (!group.sourceSymbolName || !group.sourceMemoryArea) return group
  90. const completion = findStructCompletion(group, catalog)
  91. if (!completion || !completion.registers || !completion.registers.length) {
  92. skippedCount += 1
  93. return group
  94. }
  95. const expectedBytes = Number(group.sourceByteLength || group.byteLength || 0)
  96. const actualBytes = getRegistersByteLength(completion.registers)
  97. if (expectedBytes > 0 && actualBytes !== expectedBytes && options.strictLength !== false) {
  98. skippedCount += 1
  99. return group
  100. }
  101. completedCount += 1
  102. return normalizeGroup({
  103. ...group,
  104. layout: 'struct',
  105. quantity: completion.registers.length,
  106. registers: createCompletedRegisters(group, completion)
  107. })
  108. })
  109. return {
  110. completedCount,
  111. groups: nextGroups,
  112. skippedCount,
  113. structCount: catalog.structs.length,
  114. variableCount: Object.keys(catalog.variablesByName).length
  115. }
  116. }
  117. function parseStructDefinition(sourceText) {
  118. return parseStructDefinitionSource(sourceText)
  119. }
  120. module.exports = {
  121. completeStructInstanceGroups,
  122. getRegistersByteLength,
  123. parseStructDefinition
  124. }