ocoge/local_modules/ocoge_lgpio/ocoge_lgpio.cpp
2021-09-07 21:18:50 +09:00

499 lines
14 KiB
C++

/** lgpio を Node.js から利用するモジュール ** */
/** 関数名・書式は lgpio Python に準拠 ******************* */
#include <napi.h>
#include <lgpio.h>
#include <unistd.h>
#include <string>
using namespace Napi;
// gpiochipデバイスを開く
Value gpiochipOpen(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 1)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int gpioDev = info[0].As<Number>().DoubleValue();
return Number::New(env, lgGpiochipOpen(gpioDev));
}
// gpiochipデバイスを閉じる
Value gpiochipClose(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 1)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
return Number::New(env, lgGpiochipClose(handle));
}
// GPIO のモードを出力にする(ことを要求?)
Value gpioClaimOutput(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 2)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int gpio = info[1].As<Number>().DoubleValue();
return Number::New(env,
lgGpioClaimOutput(handle, 0, gpio, 0)
);
}
// GPIO のモードを入力にする(ことを要求?)
Value gpioClaimInput(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 3)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int gpio = info[1].As<Number>().DoubleValue();
unsigned int lflag = info[2].As<Number>().DoubleValue();
return Number::New(env,
lgGpioClaimInput(handle, lflag, gpio)
);
}
// GPIOの電圧を読む
Value gpioRead(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 2)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int gpio = info[1].As<Number>().DoubleValue();
return Number::New(env,
lgGpioRead(handle, gpio)
);
}
// GPIO の電圧をセットする
Value gpioWrite(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 3)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int gpio = info[1].As<Number>().DoubleValue();
unsigned int level = info[2].As<Number>().DoubleValue();
return Number::New(env,
lgGpioWrite(handle, gpio, level)
);
}
// サーボパルス幅をセットする
Value txServo(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 3)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int gpio = info[1].As<Number>().DoubleValue();
unsigned int pulseWidth = info[2].As<Number>().DoubleValue();
return Number::New(env,
lgTxServo(handle, gpio, pulseWidth, 50, 0, 0)
);
}
// PWMを設定して出力
Value txPwm(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 4)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber() || !info[3].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int gpio = info[1].As<Number>().DoubleValue();
unsigned int pwmFrequency = info[2].As<Number>().DoubleValue();
unsigned int pwmDutyCycle = info[3].As<Number>().DoubleValue();
return Number::New(env,
lgTxPwm(handle, gpio, pwmFrequency, pwmDutyCycle, 0,0)
);
}
// シリアルポートを開く
Value serialOpen(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 2)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsString() || !info[1].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
std::string tty = info[0].As<String>().Utf8Value();
// char *c = new char[ser_tty.size()+1];
// std::strcpy(c, ser_tty.c_str());
// &ser_tty[0] で参照できるらしいけど危険?
unsigned int baud = info[1].As<Number>().DoubleValue();
return Number::New(env,
lgSerialOpen(&tty[0], baud, 0)
);
}
// シリアルポートを閉じる
Value serialClose(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 1)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
return Number::New(env,
lgSerialClose(handle)
);
}
// シリアルデバイスからデータを受け取る
Value SerialRead(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 2)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int count = info[1].As<Number>().DoubleValue();
char rxBuf[count+1];
for (unsigned int i = 0; i <= count; i++)
{
rxBuf[i] = 0;
}
lgSerialRead(handle, rxBuf, count);
return String::New(env,
rxBuf
);
}
// シリアルデバイスにバイト列を送る(data: string)
Value serialWrite(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 2)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsString())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
std::string txBuf = info[1].As<String>().Utf8Value();
unsigned int count = txBuf.length();
return Number::New(env,
lgSerialWrite(handle, &txBuf[0], count)
);
}
// I2Cバスアドレスのデバイスのハンドルを返す
Value i2cOpen(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 2)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int i2cDev = info[0].As<Number>().DoubleValue();
unsigned int i2cAddr = info[1].As<Number>().DoubleValue();
return Number::New(env,
lgI2cOpen(i2cDev, i2cAddr, 0)
);
}
// オープン済みI2Cハンドルを閉じる
Value i2cClose(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 1)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
return Number::New(env,
lgI2cClose(handle)
);
}
// デバイスに1バイトを送る
Value i2cWriteByte(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 2)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int byteVal = info[1].As<Number>().DoubleValue();
return Number::New(env,
lgI2cWriteByte(handle, byteVal)
);
}
// デバイスから1バイトを受け取る
Value i2cReadByte(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 1)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
return Number::New(env,
lgI2cReadByte(handle)
);
}
// I2Cハンドルに関連付けられているデバイスの指定されたレジスタに1バイトを書き込む
Value i2cWriteByteData(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 3)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int i2cReg = info[1].As<Number>().DoubleValue();
unsigned int byteVal = info[2].As<Number>().DoubleValue();
return Number::New(env,
lgI2cWriteByteData(handle, i2cReg, byteVal)
);
}
// I2Cハンドルに関連付けられているデバイスの指定されたレジスタから1バイトを読み込む
Value i2cReadByteData(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 2)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int i2cReg = info[1].As<Number>().DoubleValue();
return Number::New(env,
lgI2cReadByteData(handle, i2cReg)
);
}
/*
// I2Cハンドルに関連付けられているデバイスの指定されたレジスタから単一の16ビットワードを読み取る
Value I2cReadWordData(const CallbackInfo& info)
{
Env env = info.Env();
if (info.Length() < 2)
{
TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber())
{
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
unsigned int handle = info[0].As<Number>().DoubleValue();
unsigned int i2c_reg = info[1].As<Number>().DoubleValue();
return Number::New(env,
i2c_read_word_data(pi, handle, i2c_reg)
);
}
*/
Object
Init(Env env, Object exports)
{
exports.Set(String::New(env, "gpiochip_open"), Function::New(env, gpiochipOpen));
exports.Set(String::New(env, "gpiochip_close"), Function::New(env, gpiochipClose));
exports.Set(String::New(env, "gpio_claim_input"), Function::New(env, gpioClaimInput));
exports.Set(String::New(env, "gpio_claim_output"), Function::New(env, gpioClaimOutput));
exports.Set(String::New(env, "gpio_read"), Function::New(env, gpioRead));
exports.Set(String::New(env, "gpio_write"), Function::New(env, gpioWrite));
exports.Set(String::New(env, "tx_servo"), Function::New(env, txServo));
exports.Set(String::New(env, "tx_pwm"), Function::New(env, txPwm));
exports.Set(String::New(env, "serial_open"), Function::New(env, serialOpen));
exports.Set(String::New(env, "serial_close"), Function::New(env, serialClose));
exports.Set(String::New(env, "serial_read"), Function::New(env, SerialRead));
exports.Set(String::New(env, "serial_write"), Function::New(env, serialWrite));
exports.Set(String::New(env, "i2c_open"), Function::New(env, i2cOpen));
exports.Set(String::New(env, "i2c_close"), Function::New(env, i2cClose));
exports.Set(String::New(env, "i2c_write_byte"), Function::New(env, i2cWriteByte));
exports.Set(String::New(env, "i2c_read_byte"), Function::New(env, i2cReadByte));
exports.Set(String::New(env, "i2c_write_byte_data"), Function::New(env, i2cWriteByteData));
exports.Set(String::New(env, "i2c_read_byte_data"), Function::New(env, i2cReadByteData));
// exports.Set(String::New(env, "i2c_read_word_data"), Function::New(env, I2cReadWordData));
return exports;
}
NODE_API_MODULE( ocoge_lgpio, Init )