Skip to content

Instantly share code, notes, and snippets.

@pabloko
Created April 28, 2021 16:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pabloko/2cc22e9275bf63438e4c7caeb8127f19 to your computer and use it in GitHub Desktop.
Save pabloko/2cc22e9275bf63438e4c7caeb8127f19 to your computer and use it in GitHub Desktop.
Lua 5.1 / luajit - Usb HID library (hidapi) [win/mac/linux]
//using hidapi library: https://github.com/signal11/hidapi/ by Alan Ott
#include <stdio.h>
#include <malloc.h>
#include "hidapi.h"
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "hidapi.lib")
#include <Windows.h>
#include <lua.hpp>
#pragma comment(lib, "lua5.1.lib")
unsigned char buffer[0xFFF] = { 0 };
//utf8->wide helper (libcurl)
wchar_t *_convert_UTF8_to_wchar (const char *str_utf8)
{
wchar_t *str_w = NULL;
if ( str_utf8 )
{
int str_w_len = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
str_utf8, -1, NULL, 0);
if ( str_w_len > 0 )
{
str_w = ( wchar_t * )malloc (str_w_len * sizeof (wchar_t));
if ( str_w )
{
if ( MultiByteToWideChar (CP_UTF8, 0, str_utf8, -1, str_w,
str_w_len) == 0 )
{
free (str_w);
return NULL;
}
}
}
}
return str_w;
}
//wide->utf8 helper (libcurl)
char *_convert_wchar_to_UTF8 (const wchar_t *str_w)
{
char *str_utf8 = NULL;
if ( str_w )
{
int str_utf8_len = WideCharToMultiByte (CP_UTF8, 0, str_w, -1, NULL,
0, NULL, NULL);
if ( str_utf8_len > 0 )
{
str_utf8 = ( char * )malloc (str_utf8_len * sizeof (wchar_t));
if ( str_utf8 )
{
if ( WideCharToMultiByte (CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len,
NULL, FALSE) == 0 )
{
free (str_utf8);
return NULL;
}
}
}
}
return str_utf8;
}
BOOL luaopen_usbhid (lua_State* L)
{
#define LUA_TB(x) x, [] (lua_State *L) -> int
const luaL_reg tab_funcs_hid[] = {
{ LUA_TB ("Enumerate") {
hid_enumerate (0,0);
hid_device_info *dinfo = hid_enumerate (lua_tonumber(L, 1), lua_tonumber (L, 2));
hid_device_info *diterator = dinfo;
int _count = 0;
while ( diterator != NULL )
{
_count++;
diterator = diterator->next;
}
lua_createtable (L, _count, 0);
int _step = 1; //lua starts on 1 :P
while ( dinfo != NULL )
{
lua_pushnumber (L, _step);
_step++;
lua_createtable (L, 0, 10);
lua_pushstring (L, dinfo->path);
lua_setfield (L, -2, "path");
lua_pushnumber (L, dinfo->vendor_id);
lua_setfield (L, -2, "vid");
lua_pushnumber (L, dinfo->product_id);
lua_setfield (L, -2, "pid");
char *str = _convert_wchar_to_UTF8 (dinfo->serial_number);
lua_pushstring (L, str);
lua_setfield (L, -2, "serial");
free (str);
lua_pushnumber (L, dinfo->release_number);
lua_setfield (L, -2, "release_number");
str = _convert_wchar_to_UTF8 (dinfo->manufacturer_string);
lua_pushstring (L, str);
lua_setfield (L, -2, "manufacturer_string");
free (str);
str = _convert_wchar_to_UTF8 (dinfo->product_string);
lua_pushstring (L, str);
lua_setfield (L, -2, "product_string");
free (str);
lua_pushnumber (L, dinfo->usage_page);
lua_setfield (L, -2, "usage_page");
lua_pushnumber (L, dinfo->usage);
lua_setfield (L, -2, "usage");
lua_pushnumber (L, dinfo->interface_number);
lua_setfield (L, -2, "interface_number");
lua_settable (L, -3);
dinfo = dinfo->next;
}
hid_free_enumeration (dinfo);
return 1;
}},
{ LUA_TB ("Open") {
wchar_t *_serial = _convert_UTF8_to_wchar (lua_tostring (L, 3));
hid_device *hid = hid_open (lua_tonumber(L, 1),lua_tonumber(L, 2), _serial);
free (_serial);
if ( hid != NULL )
lua_pushlightuserdata (L, hid);
else
lua_pushnil (L);
return 1;
}},
{ LUA_TB ("OpenPath") {
hid_device *hid = hid_open_path (lua_tostring (L, 1));
if ( hid != NULL )
lua_pushlightuserdata (L, hid);
else
lua_pushnil (L);
return 1;
}},
{ LUA_TB ("Write") {
hid_device *hid = (hid_device*)lua_touserdata (L, 1);
size_t _size = 0;
const unsigned char *_buf = (const unsigned char*)lua_tolstring (L, 2, &_size);
size_t _written = hid_write (hid, _buf, _size);
lua_pushnumber (L, _written);
return 1;
}},
{ LUA_TB ("ReadTimeout") {
hid_device *hid = ( hid_device * )lua_touserdata (L, 1);
size_t _read = hid_read_timeout (hid, buffer, sizeof (buffer), lua_tonumber (L, 2));
lua_pushlstring (L, (const char*)buffer, _read);
return 1;
}},
{ LUA_TB ("Read") {
hid_device *hid = ( hid_device * )lua_touserdata (L, 1);
size_t _read = hid_read (hid, buffer, sizeof (buffer));
lua_pushlstring (L, ( const char * )buffer, _read);
return 1;
}},
{ LUA_TB ("SetNonBlocking") {
hid_device *hid = ( hid_device * )lua_touserdata (L, 1);
lua_pushnumber (L, hid_set_nonblocking (hid, lua_tonumber (L, 2)));
return 1;
}},
{ LUA_TB ("SendFeatureReport") {
hid_device *hid = ( hid_device * )lua_touserdata (L, 1);
size_t _size = 0;
const unsigned char *_buf = ( const unsigned char * )lua_tolstring (L, 2, &_size);
size_t _written = hid_send_feature_report (hid, _buf, _size);
lua_pushnumber (L, _written);
return 1;
}},
{ LUA_TB ("GetFeatureReport") {
hid_device *hid = ( hid_device * )lua_touserdata (L, 1);
size_t _read = hid_get_feature_report (hid, buffer, sizeof (buffer));
lua_pushlstring (L, ( const char * )buffer, _read);
return 1;
}},
{ LUA_TB ("Close") {
hid_device *hid = ( hid_device * )lua_touserdata (L, 1);
hid_close (hid);
return 0;
}},
{ LUA_TB ("Error") {
hid_device *hid = ( hid_device * )lua_touserdata (L, 1);
lua_pushnumber (L, 1);
char *err = _convert_wchar_to_UTF8(hid_error (hid));
lua_pushstring (L, err);
free (err);
return 1;
}},
{ LUA_TB ("Init") {
lua_pushnumber (L, hid_init ());
return 1;
}},
{ LUA_TB ("Exit") {
lua_pushnumber (L, hid_exit ());
return 1;
}},
{ NULL, NULL }
};
luaL_openlib (L, "HID", tab_funcs_hid, NULL);
return TRUE;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hid_init ();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
hid_exit ();
break;
}
return TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment