C++ macro oriented framework in single header file for easier export of ioctl numbers to JavaScript and TypeScript. Removes the need of building native C++ Node.js Addons
Installation
Install with npm:
$ npm install ioctl-enum
Usage
Before including the header file:
#include"node_modules/ioctl-enum/ioctl-enum.h"
Define for which language you want to export for: (JavaScript, TypeScript or both) (see FAQ why defines must be before including the header):
And then require and use the generated const enum:
// In TypeScript
import{ARA_TESTER}from'./ARA_TESTER';
console.log(ARA_TESTER.ARA_TESTER_EXEC);
Both:
Just add both defines before any including:
#defineIOCTL_ENUM_JS
#defineIOCTL_ENUM_TS
For full working example code visit: (https://github.com/NoHomey/nodejs-ioctl-example)
Warning
Add ioctl-enum's ioctls exporting to your building. Generate the TypeScript enum/ JavaScript object for each machine your project will be running at, ioctl-enum just uses the result of _IO, _IOR, _IOW, _IOWR macros wich is unsigned long C number and it differs at different Unixes, Distributions and versions. Just like you would build the native C++ Addon that wrapps the ioctl numbers on each machine !!!
This is why:
// Ran on my laptop (Ubuntu 16.04)
// ARA_TESTER.ts
exportconstenumARA_TESTER{
ARA_TESTER_PAUSE=16128,
ARA_TESTER_RESUME=16129,
ARA_TESTER_SET_DIR=1074282242,
ARA_TESTER_SET_T_MAX=1074282243,
ARA_TESTER_SET_T_MIN=1074282244,
ARA_TESTER_SET_T_DELTA=1074282245,
ARA_TESTER_SET_LINEAR=1074282246,
ARA_TESTER_GET_ACTIVE=2148024071,
ARA_TESTER_GET_PAUSE=2148024072,
ARA_TESTER_GET_TOTAL=2148024073,
ARA_TESTER_GET_COUNTER=2148024074,
ARA_TESTER_GET_MOVMENT_STATE=2148024075,
ARA_TESTER_EXEC=2148024076
};
// Ran on my Raspberry Pi 2 B+ (Raspbian May 2016 2016-05-27 4.4.1.17)
// ARA_TESTER.ts
exportconstenumARA_TESTER{
ARA_TESTER_PAUSE=16128,
ARA_TESTER_RESUME=16129,
ARA_TESTER_SET_DIR=1074020098,
ARA_TESTER_SET_T_MAX=1074020099,
ARA_TESTER_SET_T_MIN=1074020100,
ARA_TESTER_SET_T_DELTA=1074020101,
ARA_TESTER_SET_LINEAR=1074020102,
ARA_TESTER_GET_ACTIVE=2147761927,
ARA_TESTER_GET_PAUSE=2147761928,
ARA_TESTER_GET_TOTAL=2147761929,
ARA_TESTER_GET_COUNTER=2147761930,
ARA_TESTER_GET_MOVMENT_STATE=2147761931,
ARA_TESTER_EXEC=2147761932
};
FAQ
Why using ioctl-enum instead of writing C++ addon ?
A: Well beacuse just for exporting N ioctl numbers to Node.js you will write alot of code for just creating a JavaScript Object why not let ioctl-enum do it for you ? Also exporting with ioctl-enum is going to cost you N + 4 lines of code just to export you ioctls so you can controll your device driver from Node.js.
Q: Why defines must be before including the header file ?
A: Because they tell the framework for which language to implement exporting functionality.
The header file is structured like this:
Which is the only way to simulate the language agnostic construction:
if(X) {
/* ... */
}
Also this way the code is modular it's easy to add more exporting formats for more languages (eg. JSON).
Q: Why g++ is the only supported compiler ?
A: Alot of gcc and respectively g++ hacks are used in to make the framework as easy to use as possible (eg. operators #, ##) Also g++ is avalible for all unixes and unix is the platform where ioctls are used in first place so there shouldn't be a problem whith g++ beeing required.
Q: Which versions of g++ are supported ?
A: g++ with version above 4.8 is garanted to work since it's C++11 future complete.
Earlier versions may work as well infact any version that supports std::to_string will work.
Q: How ioctl-enum works ?
A: Using IOCTL_ENUM, IOCTL_ENUM_IOCTL and IOCTL_ENUM_EXPORT forms a whole C++ program that has it's own int main function wich generates strings as you use IOCTL_ENUM and IOCTL_ENUM_IOCTL and than writes these strings to files when you call IOCTL_ENUM_EXPORT.
Under the hood: this is how int main function would looked like if ioctl numbers from exaple were exported both to JavaScript and TypeScript:
var remove ='\n\# [0-9]+ \"'+ program +'\"( [0-9]+ [0-9]+)?\n';
out =out.substr(out.indexOf("int main"),out.length);
out =out.replace(newRegExp(remove,'g'),'');
out =out.replace(/; /g,';\n');
out =out.replace(/ std::ofstream/g,'\nstd::ofstream');
for(var c of'stdfor'){
out =out.replace(newRegExp('\n'+ c,'g'),'\n\t'+ c);
}
console.log(out);
}
});
Q: Why ioctl_enum.h ends with two new lines?
A: Because last charecter in it is \ and according to C and C++ standart:
If a source file that is not empty does not end in a new-line character, or ends in a new-line character immediately preceded by a backslash character, the behavior is undefined.
Also gcc and g++ respectivly both warns about this, so to be able to have fully generated int main this is a requirement.