回忆一下,我们已经完成了addon的相关学习了
详解Node.js API系列C/C++ Addons(1) API文档
详解Node.js API系列C/C++ Addons(2) Google V8引擎
详解Node.js API系列C/C++ Addons(3) 程序实例
利用这些知识,让我们做一些疯狂的事情吧,
利用Node.js控制嵌入式系统硬件。
工作原理
利用Node.js的Addon模块作为调用硬件控制C库的中间件,Node.js异步的特性,非常适合处理各种硬件的IO。本次实践使用的是cubieboard的开发板,Node.js将会控制板子的GPIO的PD0,让它1000ms产生一个高低电平,使LED灯能够一闪一闪的样子。
执行代码
vi run.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 1var GPIO = require('./build/Release/gpio');
2
3var LED = GPIO.PD0;
4var status = 0;
5GPIO.init();
6
7GPIO.setcfg(LED, GPIO.OUT);
8
9// 让led 一闪一闪
10var blink = function(){
11 if(status){
12 GPIO.output(LED, GPIO.LOW);
13 status = 0;
14 } else {
15 GPIO.output(LED, GPIO.HIGH);
16 status = 1;
17 }
18}
19
20setInterval(blink, 1000);
21
vi gpio.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 1#include <node.h>
2// 调用cubieboard的硬件控制库
3extern "C"{
4#include "gpio_lib.h"
5}
6// 定义一些工具宏
7#define WIRING_DEFINE_CONSTANT(NAME, VALUE) (target)->Set( \
8 v8::String::NewSymbol(NAME), \
9 v8::Integer::New(VALUE), \
10 static_cast<v8::PropertyAttribute>(v8::ReadOnly|v8::DontDelete) \
11);
12#define PD0 SUNXI_GPD(0)
13using namespace v8;
14// 初始化gpio的寄存器
15Handle<Value> GPIO_init(const Arguments& args) {
16 HandleScope scope;
17 int32_t result;
18 result = sunxi_gpio_init();
19 if(result == SETUP_DEVMEM_FAIL){
20 return ThrowException(
21 Exception::TypeError(String::New("SETUP_DEVMEM_FAIL Error"))
22 );
23 }
24 if(result == SETUP_MALLOC_FAIL){
25 return ThrowException(
26 Exception::TypeError(String::New("SETUP_MALLOC_FAIL Error"))
27 );
28 }
29 if(result == SETUP_MMAP_FAIL){
30 return ThrowException(
31 Exception::TypeError(String::New("SETUP_MMAP_FAIL Error"))
32 );
33 }
34 return scope.Close(Integer::New(SETUP_OK));
35}
36Handle<Value> GPIO_cleanup(const Arguments& args) {
37 HandleScope scope;
38 sunxi_gpio_cleanup();
39 return scope.Close(Undefined());
40}
41// 获取引脚当状态 IN,OUT,PRE?
42Handle<Value> GPIO_getcfg(const Arguments& args) {
43 HandleScope scope;
44
45 if (args.Length() < 1){
46 return ThrowException(
47 Exception::TypeError(String::New("Wrong number of arguments"))
48 );
49 }
50 if (!args[0]->IsNumber()){
51 return ThrowException(
52 Exception::TypeError(String::New("Wrong arguments"))
53 );
54 }
55 int32_t result;
56 int32_t gpio = args[0]->ToInteger()->Value();
57 result = sunxi_gpio_get_cfgpin(gpio);
58 return scope.Close(Integer::New(result));
59}
60// 读取的电平状态 HIGH?LOW?
61Handle<Value> GPIO_input(const Arguments& args) {
62 HandleScope scope;
63 if (args.Length() < 1){
64 return ThrowException(
65 Exception::TypeError(String::New("Wrong number of arguments"))
66 );
67 }
68 if (!args[0]->IsNumber()){
69 return ThrowException(
70 Exception::TypeError(String::New("Wrong arguments"))
71 );
72 }
73 int32_t result;
74 int32_t gpio = args[0]->ToInteger()->Value();
75 result = sunxi_gpio_input(gpio);
76 if(result == -1){
77 return ThrowException(
78 Exception::TypeError(String::New("Reading pin failed"))
79 );
80 }
81 return scope.Close(Integer::New(result));
82}
83
84// 输出电平
85Handle<Value> GPIO_output(const Arguments& args) {
86 HandleScope scope;
87 if (args.Length() < 2){
88 return ThrowException(
89 Exception::TypeError(String::New("Wrong number of arguments"))
90 );
91 }
92 if (!args[0]->IsNumber() || !args[1]->IsNumber()){
93 return ThrowException(
94 Exception::TypeError(String::New("Wrong arguments"))
95 );
96 }
97 int32_t gpio = args[0]->ToInteger()->Value();
98 int32_t value = args[1]->ToInteger()->Value();
99 if( value != 0 && value != 1) {
100 return ThrowException(
101 Exception::TypeError(String::New("Invalid output state"))
102 );
103 }
104 if(sunxi_gpio_get_cfgpin(gpio) != SUNXI_GPIO_OUTPUT) {
105 return ThrowException(
106 Exception::TypeError(String::New("Invalid output state"))
107 );
108 }
109 sunxi_gpio_output(gpio, value);
110 return scope.Close(Undefined());
111}
112// 设置GPIO功能 IN?OUT?PRE?
113Handle<Value> GPIO_setcfg(const Arguments& args) {
114 HandleScope scope;
115 if (args.Length() < 2){
116 return ThrowException(
117 Exception::TypeError(String::New("Wrong number of arguments"))
118 );
119 }
120 if (!args[0]->IsNumber() || !args[1]->IsNumber()){
121 return ThrowException(
122 Exception::TypeError(String::New("Wrong arguments"))
123 );
124 }
125 int32_t gpio = args[0]->ToInteger()->Value();
126 int32_t direction = args[1]->ToInteger()->Value();
127 if(direction != 0 && direction != 1 && direction != 2) {
128 return ThrowException(
129 Exception::TypeError(String::New("Invalid direction"))
130 );
131 }
132 sunxi_gpio_set_cfgpin(gpio, direction);
133 return scope.Close(Undefined());
134}
135void RegisterModule(Handle<Object> target) {
136 NODE_SET_METHOD(target, "init", GPIO_init);
137 NODE_SET_METHOD(target, "cleanup", GPIO_cleanup);
138 NODE_SET_METHOD(target, "output", GPIO_output);
139 NODE_SET_METHOD(target, "setcfg", GPIO_setcfg);
140 NODE_SET_METHOD(target, "input", GPIO_input);
141 NODE_SET_METHOD(target, "getcfg", GPIO_getcfg);
142 WIRING_DEFINE_CONSTANT("HIGH", HIGH)
143 WIRING_DEFINE_CONSTANT("LOW", LOW)
144 WIRING_DEFINE_CONSTANT("PD0", PD0)
145 WIRING_DEFINE_CONSTANT("IN", INPUT)
146 WIRING_DEFINE_CONSTANT("OUT", OUTPUT)
147 WIRING_DEFINE_CONSTANT("PER", PER)
148}
149NODE_MODULE(gpio, RegisterModule);
150
vi binding.gyp
1
2
3 1{
2 "targets": [ { "target_name": "gpio", "include_dirs": ["lib"], "sources": [ "gpio.cpp", "lib/gpio_lib.c", "lib/gpio_lib.h" ] } ] }
3
测试
利用万用表对准 GND 和 PD0,可以发现程序运行后,电压3V – 0V 每隔1000ms产生一次变化,如果接上LED,LED就会一闪一闪的样子。打算去买一块面包板,演示一下。
视频 演示