添加遥控业务代码
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const root = path.resolve(__dirname, '../..');
|
||||
const document = fs.readFileSync(path.join(root, 'docs/104/IEC104_API接口汇总.md'), 'utf8');
|
||||
const headers = [];
|
||||
function walk(folder) {
|
||||
for (const entry of fs.readdirSync(folder, { withFileTypes: true })) {
|
||||
const location = path.join(folder, entry.name);
|
||||
if (entry.isDirectory()) walk(location);
|
||||
else if (entry.name.endsWith('.h') && !entry.name.endsWith('_Internal.h')) headers.push(location);
|
||||
}
|
||||
}
|
||||
walk(path.join(root, '104'));
|
||||
walk(path.join(root, 'common'));
|
||||
const stripComments = source => source.replace(/\/\*[\s\S]*?\*\//g, '')
|
||||
.replace(/\/\/[^\n]*/g, '')
|
||||
.replace(/__attribute__\s*\(\(format\(printf,\s*2,\s*3\)\)\)/g, '');
|
||||
const signaturePattern = /^[ \t]*((?:extern\s+)?(?:const\s+)?[A-Za-z_]\w*(?:[ \t]+[A-Za-z_]\w*)*[ \t*]+(IEC(?:104|60870)_[A-Za-z0-9_]+)\s*\([^;{}]*\)\s*;)/gm;
|
||||
const tokens = source => (source.replace(/^extern\s+/, '').match(/[A-Za-z_][A-Za-z0-9_]*|[0-9]+|[^\s]/g) || []).join(' ');
|
||||
const declarationOnly = new Set(['IEC60870_Clock_RTC_Read', 'IEC60870_Clock_RTC_Set']);
|
||||
const documented = new Map();
|
||||
for (const block of document.matchAll(/```c\n([\s\S]*?)```/g)) {
|
||||
for (const match of stripComments(block[1]).matchAll(signaturePattern)) {
|
||||
if (/^typedef\b/.test(match[1])) continue;
|
||||
if (!documented.has(match[2])) documented.set(match[2], new Set());
|
||||
documented.get(match[2]).add(tokens(match[1]));
|
||||
}
|
||||
}
|
||||
const missing = [], mismatched = [];
|
||||
let checked = 0;
|
||||
for (const header of headers) {
|
||||
for (const match of stripComments(fs.readFileSync(header, 'utf8')).matchAll(signaturePattern)) {
|
||||
if (/^typedef\b/.test(match[1])) continue;
|
||||
const name = match[2];
|
||||
if (declarationOnly.has(name)) continue;
|
||||
++checked;
|
||||
if (!documented.has(name)) missing.push({ header: path.relative(root, header), name });
|
||||
else if (!documented.get(name).has(tokens(match[1]))) {
|
||||
mismatched.push({ header: path.relative(root, header), name, declaration: match[1], documented: [...documented.get(name)] });
|
||||
}
|
||||
}
|
||||
}
|
||||
const commandHeader = stripComments(fs.readFileSync(path.join(root, '104/business/IEC104_Command.h'), 'utf8'));
|
||||
const commandReference = document.slice(document.indexOf('## 25. IEC104_Command.c'));
|
||||
const missingFields = [];
|
||||
let checkedCommandFields = 0;
|
||||
for (const structure of commandHeader.matchAll(/typedef\s+struct\s*\{([^{}]*)\}\s*(IEC104_Command\w+_t)\s*;/g)) {
|
||||
for (const declaration of structure[1].split(';').map(x => x.trim()).filter(Boolean)) {
|
||||
const names = declaration.split(',').map(x => /([A-Za-z_]\w*)\s*$/.exec(x)[1]);
|
||||
for (const name of names) {
|
||||
++checkedCommandFields;
|
||||
if (!new RegExp(`\\b${name}\\b`).test(commandReference)) missingFields.push(`${structure[2]}.${name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(JSON.stringify({ checked, documented: documented.size, declarationOnly: [...declarationOnly],
|
||||
missing, mismatched, checkedCommandFields, missingFields }, null, 2));
|
||||
process.exitCode = missing.length || mismatched.length || missingFields.length ? 1 : 0;
|
||||
@@ -0,0 +1,46 @@
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const assert = require('node:assert/strict');
|
||||
const root = path.resolve(__dirname, '../..');
|
||||
const files = ['docs/104/IEC104_API接口汇总.md', 'docs/104/IEC104_完整调用流程.md'];
|
||||
for (const file of files) {
|
||||
const bytes = fs.readFileSync(path.join(root, file));
|
||||
const source = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
|
||||
const baseline = fs.readFileSync(path.join(__dirname, path.basename(file) + '.before'));
|
||||
assert.equal(bytes.subarray(0, 3).equals(Buffer.from([0xef, 0xbb, 0xbf])),
|
||||
baseline.subarray(0, 3).equals(Buffer.from([0xef, 0xbb, 0xbf])), `${file}: BOM changed`);
|
||||
assert(!source.includes('\ufffd') && !source.includes('\r'), `${file}: encoding or line ending`);
|
||||
assert(source.endsWith('\n') && !/[\t ]+$/m.test(source), `${file}: whitespace`);
|
||||
const ids = new Set();
|
||||
let fence = '', details = 0, blocks = 0;
|
||||
const tableProblems = [];
|
||||
let tableColumns = 0;
|
||||
for (const [index, line] of source.split('\n').entries()) {
|
||||
const marker = /^(`{3,}|~{3,})/.exec(line);
|
||||
if (marker) {
|
||||
if (!fence) { fence = marker[1]; blocks++; }
|
||||
else if (marker[1][0] === fence[0] && marker[1].length >= fence.length) fence = '';
|
||||
tableColumns = 0;
|
||||
continue;
|
||||
}
|
||||
if (fence) continue;
|
||||
for (const match of line.matchAll(/<a\s+id="([^"]+)"\s*>/g)) {
|
||||
assert(!ids.has(match[1]), `${file}:${index + 1}: duplicate id ${match[1]}`);
|
||||
ids.add(match[1]);
|
||||
}
|
||||
if (line.includes('<details>')) details++;
|
||||
if (line.includes('</details>')) details--;
|
||||
assert(details >= 0, `${file}:${index + 1}: unexpected details close`);
|
||||
if (/^\|/.test(line)) {
|
||||
const columns = (line.replace(/\\\|/g, '').match(/\|/g) || []).length;
|
||||
if (tableColumns && columns !== tableColumns) tableProblems.push(index + 1);
|
||||
tableColumns = columns;
|
||||
} else tableColumns = 0;
|
||||
}
|
||||
assert(!fence && details === 0, `${file}: unclosed fence/details`);
|
||||
assert.deepEqual(tableProblems, [], `${file}: inconsistent table column count`);
|
||||
for (const id of baseline.toString('utf8').matchAll(/<a\s+id="([^"]+)"\s*>/g)) {
|
||||
assert(ids.has(id[1]), `${file}: removed existing anchor ${id[1]}`);
|
||||
}
|
||||
console.log(`${file}: ${blocks} fenced blocks, ${ids.size} stable anchors, UTF-8/LF and tables OK`);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "IEC104_Command.h"
|
||||
|
||||
static IEC104_Command_t *Create_Command(IEC104_Slave_t *slave)
|
||||
{
|
||||
IEC104_CommandConfig_t config;
|
||||
IEC104_Command_Config_Default(&config);
|
||||
return IEC104_Command_Create(slave, &config);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return Create_Command(NULL) != NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user