The InMoov project seems like the perfect platform to gain experience with programming life sized humanoid robots. Unlike most robotics projects of this scale, InMoov is open sourced and well documented. Furthermore there is an active community that is constantly making advancements. I let a few friends know about my plans and they were hyped. We already have a decent build of materials and we are currently working on getting access to 3D printers.
First Meet Up (August 2016)After a considerable amount of discussion we decided to check in with some professors about our plans. We believe they can give us insight into how best to approach this project. Since school is starting soon, we decided to hold off on printing now, so that we can use syllabus week to create a small part of the project. Our hope is that by creating and presenting a small part of the humanoid we can begin garnering support to build the full robot.
Between New York and Ibaraki (February 2017)When I first saw this project, I was actively searching for summer internship opportunities involving robotics. In less than a few weeks after our first meeting, I was offered a position in Japan for the year. The timing was unique, but I decided to make the most of the opportunity.
I thought I would have to postpone the project until I returned to the U.S., but a few of my teammates, and particularly Mike, expressed interest in continuing the project. So, I ordered the materials for us to get started, and sent them to him. This is definitely not how I imagined the project would start, but I am happy that it has started and I'm looking forward to collaborating between Ibaraki and New York.
First Week Back From Japan (Late May 2017)The parts for the hand and forearm were printed a few months ago. However, the project took a hiatus until I returned from Japan. Within my first week back, the arm was assembled, wired, and programmed for basic control. Special thanks to Mike and Kenny for doing most of the assembly, to Faith for helping me learn how to better use social media, and to Mike again for doing all of the printing. Now, I am at the Rochester Institute of Technology (RIT) for a Research Experience for Undergraduates (REU) in Computational Sensing, and I brought the robot with me.
After doing research for the day, I would often head back to the Graphics Lab at R.I.T. to play with the sensors. I was hoping to build a Hololens plugin for the Choreonoid robotics simulator, but I didn't have quite as much time as I hoped. So, I decided to put something technically less time consuming together. I used the MindWave Mobile EEG headset to open and close the InMoov robotic hand. The hand control is based on keystrokes entered into the arduino terminal. So, I explored various SDK's for the headset and decided to use the Algo demo and make it generate key strokes. In terms of software development, this is relatively straightforward, however, it made for a provocative demonstration at the Greece public library. I'm back at University at Buffalo now and I've assembled a team in my software engineering class (CSE 442) to build a Choreonoid plugin for testing InMoov leg designs. We decided to keep the MVP simple, but we'll see how far we can get in a semester.
InMoov for Choreonoid (September 2017 - January 2018)
The first 15 weeks of this mini-project were focused on the requirements of CSE 442. In that class we had to develop and deploy a software project of our choosing. After revising our team contract for the third time, I realized that InMoov - 442 was transforming into something quite different from our original intentions. Although, things didn't go quite as planned, we learned a lot from the experience, and I decided to continue and revise InMoov - 442 into InMoov for Choreonoid. So, after the semester ended, I pulled together a small team in Lockport and assembled the InMoov model in Choreonoid. Here is a video of the finished model. Now, I am exploring control methods and learning about the iterative linear quadratic regulator algorithm for my independent study.
Basic Hand Control
C/C++#include <Servo.h>;
Servo servothumb; // Define thumb servo
Servo servoindex; // Define index servo
Servo middle;
Servo servoringfinger;
Servo servopinky;
Servo servowrist;
Servo servobiceps;
Servo servorotate;
Servo servoshoulder;
Servo servoomoplat;
Servo servoneck;
Servo servorothead;
char c;
int Open = 150;
int Close = 50;
//Fingers start closed
int rightThumb = 160;
int rightIndex = 170;
int rightMiddle = 160;
int rightRing = 0;
int rightPinky = 160;
int rightWrist = 90;
int i = 10;
void setup() {
servothumb.attach(2); // Set thumb servo to digital pin 2
servoindex.attach(3); // Set index servo to digital pin 3
middle.attach(4);
servoringfinger.attach(5);
servopinky.attach(6);
servowrist.attach(7);
servobiceps.attach(8);
servorotate.attach(9);
servoshoulder.attach(10);
servoomoplat.attach(11);
servoneck.attach(12);
servorothead.attach(13);
Serial.begin(9600);
Serial.print("setup complete");
}
void loop() { // Loop through motion tests
c = Serial.read();
Serial.print(rightThumb);
Serial.print(' ');
Serial.print(rightIndex);
Serial.print(' ');
Serial.print(rightMiddle);
Serial.print(' ');
Serial.print(rightRing);
Serial.print(' ');
Serial.print(rightPinky);
Serial.print(' ');
Serial.println(rightWrist);
if (c=='q' || c=='Q'){rightThumb = rightThumb-i < 60 ? 60 : rightThumb-i;}
else if (c=='a' || c=='A') {rightThumb = rightThumb+i > 180 ? 180 : rightThumb+i;}
else if (c=='w' || c=='W') {rightIndex = rightIndex-i < 40 ? 40 : rightIndex-i;}
else if (c=='s' || c=='S') {rightIndex = rightIndex+i > 180 ? 180 : rightIndex+i;}
else if (c=='e' || c=='E') {rightMiddle = rightMiddle-i < 30 ? 30 : rightMiddle-i;}
else if (c=='d' || c=='D') {rightMiddle = rightMiddle+i > 180 ? 180 : rightMiddle+i;}
else if (c=='r' || c=='R') {rightRing = rightRing+i > 150 ? 150 : rightRing+i;}
else if (c=='f' || c=='F') {rightRing = rightRing-i < 0 ? 0 : rightRing-i;}
else if (c=='t' || c=='T') {rightPinky = rightPinky-i < 40 ? 40 : rightPinky-i;}
else if (c=='g' || c=='G') {rightPinky = rightPinky+i > 180 ? 180 : rightPinky+i;}
else if (c=='y'){rightWrist = rightWrist+i > 180 ? 180 : rightWrist+i;}
else if (c=='u'){rightWrist = rightWrist-i < 0 ? 0 : rightWrist-i;}
alltovirtual(); // Example: alltovirtual
delay(40); // Wait 4000 milliseconds (.04 seconds)
//alltorest(); // Uncomment to use this
//delay(4000); // Uncomment to use this
//alltomax(); // Uncomment to use this
//delay(2000); // Uncomment to use this
//allto90(); // Uncomment to use this
//delay(2000); // Uncomment to use this
}
// Motion to set the servo into "virtual" 0 position: alltovirtual
void alltovirtual() {
servothumb.write(rightThumb);
servoindex.write(rightIndex);
middle.write(rightMiddle);
servoringfinger.write(rightRing);
servopinky.write(rightPinky);
servowrist.write(rightWrist);
servobiceps.write(0);
servorotate.write(20); //Never less then (20 degree)
servoshoulder.write(30); //Never less then (30 degree)
servoomoplat.write(10); //Never less then (10 degree)
servoneck.write(0);
servorothead.write(0);
}
// Motion to set the servo into " ()" position: alltorest
void alltorest() {
servothumb.write(0);
servoindex.write(0);
middle.write(0);
servoringfinger.write(0);
servopinky.write(0);
servowrist.write(0);
servobiceps.write(0);
servorotate.write(90); //Never less then (20 degree)
servoshoulder.write(30); //Never less then (30 degree)
servoomoplat.write(10); //Never less then (10 degree)
servoneck.write(90);
servorothead.write(90);
}
// Motion to set the servo into "max" position: alltomax
void alltomax() {
servothumb.write(180);
servoindex.write(180);
middle.write(180);
servoringfinger.write(180);
servopinky.write(180);
servowrist.write(180);
servobiceps.write(85); //Never more then (85 or 90degree)
servorotate.write(110); //Never more then (110 degree)
servoshoulder.write(130); //Never more then (130 degree)
servoomoplat.write(70); //Never more then (70 degree)
servoneck.write(180);
servorothead.write(180);
}
// Motion to set the servo into "90" position: allto90
void allto90() {
servothumb.write(90);
servoindex.write(90);
middle.write(90);
servoringfinger.write(90);
servopinky.write(90);
servowrist.write(90);
servobiceps.write(90); //Never more then (85 or 90degree)
servorotate.write(90); //Never more then (110 degree)
servoshoulder.write(90); //Never more then (130 degree)
servoomoplat.write(70); //Never more then (70 degree)
servoneck.write(90);
servorothead.write(180);
}
Algo SDK Sample.cpp
C/C++// Algo SDK Sample.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "Algo SDK Sample.h"
#include "NSK_Algo.h"
#include "thinkgear.h"
#include <stdio.h>
#include <string>
#include <WinUser.h>
#include <windowsx.h>
#include <Windows.h>
#include <CommCtrl.h>
#include <time.h>
extern "C" {
void *myMalloc(size_t size) {
return malloc(size);
}
};
void * operator new (size_t size) {
return myMalloc(size);
}
#define MAX_LOADSTRING 100
#define NSK_ALGO_CDECL(ret, func, args) typedef ret (__cdecl *func##_Dll) args; func##_Dll func##Addr = NULL; char func##Str[] = #func;
NSK_ALGO_CDECL(eNSK_ALGO_RET, NSK_ALGO_Init, (eNSK_ALGO_TYPE type, const NS_STR dataPath));
NSK_ALGO_CDECL(eNSK_ALGO_RET, NSK_ALGO_Uninit, (NS_VOID));
NSK_ALGO_CDECL(eNSK_ALGO_RET, NSK_ALGO_RegisterCallback, (NskAlgo_Callback cbFunc, NS_VOID *userData));
NSK_ALGO_CDECL(NS_STR, NSK_ALGO_SdkVersion, (NS_VOID));
NSK_ALGO_CDECL(NS_STR, NSK_ALGO_AlgoVersion, (eNSK_ALGO_TYPE type));
NSK_ALGO_CDECL(eNSK_ALGO_RET, NSK_ALGO_Start, (NS_BOOL bBaseline));
NSK_ALGO_CDECL(eNSK_ALGO_RET, NSK_ALGO_Pause, (NS_VOID));
NSK_ALGO_CDECL(eNSK_ALGO_RET, NSK_ALGO_Stop, (NS_VOID));
NSK_ALGO_CDECL(eNSK_ALGO_RET, NSK_ALGO_DataStream, (eNSK_ALGO_DATA_TYPE type, NS_INT16 *data, NS_INT dataLenght));
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
HWND hInitBtn, hStartBtn, hStopBtn, hBulkDataBtn, hBlinkCheck, hAPCheck, hMECheck, hME2Check, hFCheck, hF2Check, hAttCheck, hMedCheck, hBPCheck, hStateText, hSignalQualityText, hVersionBtn, hOutputText;
HWND hWnd;
HWND hIntervalBtn, hSettingAPCheck, hSettingMECheck, hSettingME2Check, hSettingFCheck, hSettingF2Check, hIntervalSlider, hIntervalText;
int lSelectedAlgos = 0;
long raw_data_count = 0;
short *raw_data = NULL;
bool bRunning = false;
bool bInited = false;
#define MARGIN 10
#define STATE_TEXT_WIDTH 300
#define STATE_TEXT_HEIGHT 20
#define SIGNAL_TEXT_WIDTH 200
#define SIGNAL_TEXT_HEIGHT 20
#define BUTTON_WIDTH 100
#define BUTTON_HEIGHT 20
#define WM_USER 0x1000
#define WM_USER_SETTEXT WM_USER
#define MWM_COM "COM16"
#define EEG_RAW_DATA "ME_Easy_RawData.txt"
#ifdef _WIN64
#define ALGO_SDK_DLL L"AlgoSdkDll64.dll"
#else
#define ALGO_SDK_DLL L"AlgoSdkDll.dll"
#endif
char *comPortName = NULL;
int dllVersion = 0;
int connectionId = -1;
int packetsRead = 0;
int errCode = 0;
DWORD dwThreadId = -1;
HANDLE threadHandle = NULL;
bool bConnectedHeadset = false;
static DWORD ThreadReadPacket(LPVOID lpdwThreadParam);
static void AlgoSdkCallback(sNSK_ALGO_CB_PARAM param);
static bool getFuncAddrs(HINSTANCE hinstLib, HWND hWnd);
static void *getFuncAddr(HINSTANCE hinstLib, HWND hwnd, char *funcName, bool *bError);
static void OutputLog(LPCWSTR log);
static void UIComponentsPositionUpdate(HWND hWnd);
static wchar_t *GetLocalTimeStr();
static void OutputToEditBox(LPCWSTR szBuf);
static void pressAndReleaseAndEnter(int virtualKeyCode) {
// ListOfKeyCodes
// https://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx
// Simulate a key press
keybd_event(virtualKeyCode, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);
// Simulate a key release
keybd_event(virtualKeyCode, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
// Press enter
keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);
keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
static DWORD ThreadReadPacket(LPVOID lpdwThreadParam) {
int rawCount = 0;
wchar_t buffer[100];
short rawData[512] = { 0 };
int lastRawCount = 0;
while (true) {
/* Read a single Packet from the connection */
packetsRead = TG_ReadPackets(connectionId, 1);
/* If TG_ReadPackets() was able to read a Packet of data... */
if (packetsRead == 1) {
/* If the Packet containted a new raw wave value... */
if (TG_GetValueStatus(connectionId, TG_DATA_RAW) != 0) {
/* Get and print out the new raw value */
rawData[rawCount++] = (short)TG_GetValue(connectionId, TG_DATA_RAW);
lastRawCount = rawCount;
if (rawCount == 512) {
(NSK_ALGO_DataStreamAddr)(NSK_ALGO_DATA_TYPE_EEG, rawData, rawCount);
rawCount = 0;
}
}
if (TG_GetValueStatus(connectionId, TG_DATA_POOR_SIGNAL) != 0) {
short pq = (short)TG_GetValue(connectionId, TG_DATA_POOR_SIGNAL);
SYSTEMTIME st;
GetSystemTime(&st);
swprintf(buffer, 100, L"%6d, PQ[%3d], [%d]", st.wSecond*1000 + st.wMilliseconds, pq, lastRawCount);
rawCount = 0;
OutputLog(buffer);
(NSK_ALGO_DataStreamAddr)(NSK_ALGO_DATA_TYPE_PQ, &pq, 1);
}
if (TG_GetValueStatus(connectionId, TG_DATA_ATTENTION) != 0) {
short att = (short)TG_GetValue(connectionId, TG_DATA_ATTENTION);
if (att > 50) { //conentrate to open hand
pressAndReleaseAndEnter('Q');
pressAndReleaseAndEnter('W');
pressAndReleaseAndEnter('E');
pressAndReleaseAndEnter('R');
pressAndReleaseAndEnter('T');
}
else if (att < 40) { //relax to close
pressAndReleaseAndEnter('A');
pressAndReleaseAndEnter('S');
pressAndReleaseAndEnter('D');
pressAndReleaseAndEnter('F');
pressAndReleaseAndEnter('G');
}
(NSK_ALGO_DataStreamAddr)(NSK_ALGO_DATA_TYPE_ATT, &att, 1);
}
if (TG_GetValueStatus(connectionId, TG_DATA_MEDITATION) != 0) {
short med = (short)TG_GetValue(connectionId, TG_DATA_MEDITATION);
(NSK_ALGO_DataStreamAddr)(NSK_ALGO_DATA_TYPE_MED, &med, 1);
}
}
//Sleep(1);
}
}
static void OutputLog(LPCWSTR log) {
OutputDebugStringW(log);
OutputDebugStringW(L"\r\n");
}
static void *getFuncAddr(HINSTANCE hinstLib, HWND hwnd, char *funcName, bool *bError) {
void *funcPtr = (void*)GetProcAddress(hinstLib, funcName);
*bError = true;
if (NULL == funcPtr) {
wchar_t szBuff[100] = { 0 };
swprintf(szBuff, 100, L"Failed ot get %s function address", (wchar_t*)funcName);
MessageBox(hwnd, szBuff, L"Error", MB_OK);
*bError = false;
}
return funcPtr;
}
static bool getFuncAddrs(HINSTANCE hinstLib, HWND hWnd) {
bool bError;
NSK_ALGO_InitAddr = (NSK_ALGO_Init_Dll)getFuncAddr(hinstLib, hWnd, NSK_ALGO_InitStr, &bError);
NSK_ALGO_UninitAddr = (NSK_ALGO_Uninit_Dll)getFuncAddr(hinstLib, hWnd, NSK_ALGO_UninitStr, &bError);
NSK_ALGO_RegisterCallbackAddr = (NSK_ALGO_RegisterCallback_Dll)getFuncAddr(hinstLib, hWnd, NSK_ALGO_RegisterCallbackStr, &bError);
NSK_ALGO_SdkVersionAddr = (NSK_ALGO_SdkVersion_Dll)getFuncAddr(hinstLib, hWnd, NSK_ALGO_SdkVersionStr, &bError);
NSK_ALGO_AlgoVersionAddr = (NSK_ALGO_AlgoVersion_Dll)getFuncAddr(hinstLib, hWnd, NSK_ALGO_AlgoVersionStr, &bError);
NSK_ALGO_StartAddr = (NSK_ALGO_Start_Dll)getFuncAddr(hinstLib, hWnd, NSK_ALGO_StartStr, &bError);
NSK_ALGO_PauseAddr = (NSK_ALGO_Pause_Dll)getFuncAddr(hinstLib, hWnd, NSK_ALGO_PauseStr, &bError);
NSK_ALGO_StopAddr = (NSK_ALGO_Stop_Dll)getFuncAddr(hinstLib, hWnd, NSK_ALGO_StopStr, &bError);
NSK_ALGO_DataStreamAddr = (NSK_ALGO_DataStream_Dll)getFuncAddr(hinstLib, hWnd, NSK_ALGO_DataStreamStr, &bError);
return bError;
}
static wchar_t *GetLocalTimeStr() {
static wchar_t buffer[128];
SYSTEMTIME lt;
GetLocalTime(<);
wsprintf(buffer, L"%2d/%2d/%4d %02d:%02d:%02d:%03d", lt.wDay, lt.wMonth, lt.wYear, lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds);
return buffer;
}
static void OutputToEditBox(LPCWSTR szBuf) {
if (Edit_GetLineCount(hOutputText) >= 1024) {
Edit_SetSel(hOutputText, 0, -1);
Edit_ReplaceSel(hOutputText, L"");
}
wchar_t buffer[1024];
int nLength = GetWindowTextLength(hOutputText);
Edit_SetSel(hOutputText, nLength, nLength);
wsprintf(buffer, L" [%s]: %s\r\n\r\n", GetLocalTimeStr(), szBuf);
Edit_ReplaceSel(hOutputText, buffer);
}
static void AlgoSdkCallback(sNSK_ALGO_CB_PARAM param) {
static wchar_t buffer[512];
static wchar_t sbuffer[512];
static wchar_t qbuffer[512];
buffer[0] = sbuffer[0] = qbuffer[0] = 0;
switch (param.cbType) {
case NSK_ALGO_CB_TYPE_STATE:
{
HWND handle = (HWND)param.userData;
eNSK_ALGO_STATE state = (eNSK_ALGO_STATE)(param.param.state & NSK_ALGO_STATE_MASK);
eNSK_ALGO_STATE reason = (eNSK_ALGO_STATE)(param.param.state & NSK_ALGO_REASON_MASK);
swprintf(sbuffer, 512, L"State: ");
switch (state) {
case NSK_ALGO_STATE_INITED:
swprintf(sbuffer, 512, L"%sInited", sbuffer);
bRunning = false;
bInited = true;
PostMessage(hWnd, WM_ENABLE, (WPARAM)hAPCheck, (LPARAM)false);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hMECheck, (LPARAM)false);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hME2Check, (LPARAM)false);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hFCheck, (LPARAM)false);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hF2Check, (LPARAM)false);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hAttCheck, (LPARAM)false);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hMedCheck, (LPARAM)false);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hBlinkCheck, (LPARAM)false);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hBPCheck, (LPARAM)false);
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hStartBtn, (LPARAM)L"Start");
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStartBtn, (LPARAM)true);
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hInitBtn, (LPARAM)L"Uninit");
break;
case NSK_ALGO_STATE_ANALYSING_BULK_DATA:
swprintf(sbuffer, 512, L"%sAnalysing data", sbuffer);
bRunning = true;
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hStartBtn, (LPARAM)L"Pause");
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStartBtn, (LPARAM)false);
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStopBtn, (LPARAM)true);
break;
case NSK_ALGO_STATE_COLLECTING_BASELINE_DATA:
swprintf(sbuffer, 512, L"%sCollecting baseline", sbuffer);
bRunning = true;
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hStartBtn, (LPARAM)L"Pause");
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStopBtn, (LPARAM)true);
break;
case NSK_ALGO_STATE_PAUSE:
swprintf(sbuffer, 512, L"%sPause", sbuffer);
bRunning = false;
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hStartBtn, (LPARAM)L"Start");
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStopBtn, (LPARAM)false);
break;
case NSK_ALGO_STATE_RUNNING:
swprintf(sbuffer, 512, L"%sRunning", sbuffer);
bRunning = true;
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hStartBtn, (LPARAM)L"Pause");
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStopBtn, (LPARAM)true);
break;
case NSK_ALGO_STATE_RUNNING_DEMO:
swprintf(sbuffer, 512, L"%sRunning Demo", sbuffer);
bRunning = true;
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hStartBtn, (LPARAM)L"Pause");
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStopBtn, (LPARAM)true);
break;
case NSK_ALGO_STATE_STOP:
{
swprintf(sbuffer, 512, L"%sStop", sbuffer);
bRunning = false;
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hStartBtn, (LPARAM)L"Start");
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStartBtn, (LPARAM)true);
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStopBtn, (LPARAM)false);
if (bConnectedHeadset == false) {
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hBulkDataBtn, (LPARAM)true);
}
}
break;
case NSK_ALGO_STATE_UNINTIED:
swprintf(sbuffer, 512, L"%sUninited", sbuffer);
bRunning = false;
bInited = false;
//PostMessage(hWnd, WM_ENABLE, (WPARAM)hAPCheck, (LPARAM)true);
//PostMessage(hWnd, WM_ENABLE, (WPARAM)hMECheck, (LPARAM)true);
//PostMessage(hWnd, WM_ENABLE, (WPARAM)hME2Check, (LPARAM)true);
//PostMessage(hWnd, WM_ENABLE, (WPARAM)hFCheck, (LPARAM)true);
//PostMessage(hWnd, WM_ENABLE, (WPARAM)hF2Check, (LPARAM)true);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hAttCheck, (LPARAM)true);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hMedCheck, (LPARAM)true);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hBlinkCheck, (LPARAM)true);
PostMessage(hWnd, WM_ENABLE, (WPARAM)hBPCheck, (LPARAM)true);
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hStartBtn, (LPARAM)L"Start");
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStartBtn, (LPARAM)false);
PostMessageW(hWnd, WM_ENABLE, (WPARAM)hStopBtn, (LPARAM)false);
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hInitBtn, (LPARAM)L"Init");
break;
default:
return;
}
switch (reason) {
case NSK_ALGO_REASON_BY_USER:
swprintf(sbuffer, 512, L"%s | By user", sbuffer);
break;
case NSK_ALGO_REASON_CB_CHANGED:
swprintf(sbuffer, 512, L"%s | CB changed", sbuffer);
break;
case NSK_ALGO_REASON_NO_BASELINE:
swprintf(sbuffer, 512, L"%s | No baseline", sbuffer);
break;
case NSK_ALGO_REASON_SIGNAL_QUALITY:
swprintf(sbuffer, 512, L"%s | Signal quality", sbuffer);
break;
default:
break;
}
PostMessageW(hWnd, WM_USER_SETTEXT, (WPARAM)hStateText, (LPARAM)sbuffer);
}
break;
case NSK_ALGO_CB_TYPE_SIGNAL_LEVEL:
{
HWND handle = (HWND)param.userData;
eNSK_ALGO_SIGNAL_QUALITY sq = (eNSK_ALGO_SIGNAL_QUALITY)param.param.sq;
swprintf(qbuffer, 512, L"Signal Quality: ");
switch (sq) {
case NSK_ALGO_SQ_GOOD:
swprintf(qbuffer, 512, L"%sGood", qbuffer);
break;
case NSK_ALGO_SQ_MEDIUM:
swprintf(qbuffer, 512, L"%sMedium", qbuffer);
break;
case NSK_ALGO_SQ_NOT_DETECTED:
swprintf(qbuffer, 512, L"%sNot detected", qbuffer);
break;
case NSK_ALGO_SQ_POOR:
swprintf(qbuffer, 512, L"%sPoor", qbuffer);
break;
}
PostMessage(hWnd, WM_USER_SETTEXT, (WPARAM)hSignalQualityText, (LPARAM)qbuffer);
}
break;
case NSK_ALGO_CB_TYPE_ALGO:
{
switch (param.param.index.type) {
case NSK_ALGO_TYPE_ATT:
{
int att = param.param.index.value.group.att_index;
swprintf(buffer, 512, L"ATT = %3d", att);
OutputToEditBox(buffer);
OutputLog(buffer);
break;
}
case NSK_ALGO_TYPE_MED:
{
int med = param.param.index.value.group.med_index;
swprintf(buffer, 512, L"MED = %3d", med);
OutputToEditBox(buffer);
OutputLog(buffer);
break;
}
case NSK_ALGO_TYPE_BLINK:
{
int strength = param.param.index.value.group.eye_blink_strength;
swprintf(buffer, 512, L"Eye blink strength = %4d", strength);
OutputToEditBox(buffer);
OutputLog(buffer);
break;
}
case NSK_ALGO_TYPE_BP:
{
swprintf(buffer, 512, L"EEG Bandpower: Delta: %1.4f Theta: %1.4f Alpha: %1.4f Beta: %1.4f Gamma: %1.4f",
param.param.index.value.group.bp_index.delta_power,
param.param.index.value.group.bp_index.theta_power,
param.param.index.value.group.bp_index.alpha_power,
param.param.index.value.group.bp_index.beta_power,
param.param.index.value.group.bp_index.gamma_power);
OutputToEditBox(buffer);
OutputLog(buffer);
break;
}
}
}
break;
}
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_ALGOSDKSAMPLE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_ALGOSDKSAMPLE));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ALGOSDKSAMPLE));
wcex.hCursor = LoadCursor(nullptr, IDC_HAND);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_ALGOSDKSAMPLE);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
static void UIComponentsPositionUpdate(HWND hWnd) {
RECT rect;
GetClientRect(hWnd, &rect);
SetWindowPos(hInitBtn, NULL, MARGIN, MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hVersionBtn, NULL, MARGIN + MARGIN + BUTTON_WIDTH, MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hStartBtn, NULL, MARGIN, (MARGIN + BUTTON_HEIGHT) + MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hBulkDataBtn, NULL, MARGIN + BUTTON_WIDTH + MARGIN, (MARGIN + BUTTON_HEIGHT) + MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hStopBtn, NULL, MARGIN, (MARGIN + BUTTON_HEIGHT) * 2 + MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hStateText, NULL, MARGIN, rect.bottom - STATE_TEXT_HEIGHT - MARGIN, STATE_TEXT_WIDTH, STATE_TEXT_HEIGHT, SWP_NOZORDER);
SetWindowPos(hSignalQualityText, NULL, rect.right - SIGNAL_TEXT_WIDTH - MARGIN, rect.bottom - SIGNAL_TEXT_HEIGHT - MARGIN, SIGNAL_TEXT_WIDTH, SIGNAL_TEXT_HEIGHT, SWP_NOZORDER);
SetWindowPos(hMedCheck, NULL, rect.right - BUTTON_WIDTH - MARGIN, MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hAttCheck, NULL, rect.right - (BUTTON_WIDTH + MARGIN)*2, MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hBPCheck, NULL, rect.right - (BUTTON_WIDTH + MARGIN) * 3, MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hBlinkCheck, NULL, rect.right - (BUTTON_WIDTH + MARGIN) * 2, MARGIN + BUTTON_HEIGHT + MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hAPCheck, NULL, rect.right - BUTTON_WIDTH - MARGIN, MARGIN + BUTTON_HEIGHT + MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hMECheck, NULL, rect.right - BUTTON_WIDTH - MARGIN, MARGIN + (BUTTON_HEIGHT + MARGIN)*2, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hME2Check, NULL, rect.right - (BUTTON_WIDTH + MARGIN)*2, MARGIN + (BUTTON_HEIGHT + MARGIN) * 2, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hFCheck, NULL, rect.right - BUTTON_WIDTH - MARGIN, MARGIN + (BUTTON_HEIGHT + MARGIN) * 3, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hF2Check, NULL, rect.right - (BUTTON_WIDTH + MARGIN) * 2, MARGIN + (BUTTON_HEIGHT + MARGIN) * 3, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER);
SetWindowPos(hOutputText, NULL, MARGIN, MARGIN + (BUTTON_HEIGHT + MARGIN) * 4 + MARGIN, rect.right - (MARGIN * 2), rect.bottom - (MARGIN + (BUTTON_HEIGHT + MARGIN) * 4 + MARGIN) - BUTTON_HEIGHT - (MARGIN * 2), SWP_NOZORDER);
//SetWindowText(hOutputText, L"1\r\n2\r\n3\r\n");
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
HINSTANCE hinstLib = LoadLibrary(ALGO_SDK_DLL);
if (hinstLib == NULL) {
MessageBox(hWnd, L"Failed to load library AlgoSdkDll.dll", L"Error", MB_OK);
OutputLog(L"Failed to load library AlgoSdkDll.dll");
}
else {
OutputLog(L"Loaded library AlgoSdkDll.dll");
if (getFuncAddrs(hinstLib, hWnd) == false) {
FreeLibrary(hinstLib);
return FALSE;
}
//MessageBox(hWnd, L"All Algo SDK functions are loaded successfully", L"Information", MB_OK);
}
/* Get a connection ID handle to ThinkGear */
connectionId = TG_GetNewConnectionId();
if (connectionId < 0) {
MessageBox(hWnd, L"Failed to new connection ID", L"Error", MB_OK);
}
else {
/* Attempt to connect the connection ID handle to serial port "COM5" */
/* NOTE: On Windows, COM10 and higher must be preceded by \\.\, as in
* "\\\\.\\COM12" (must escape backslashes in strings). COM9
* and lower do not require the \\.\, but are allowed to include
* them. On Mac OS X, COM ports are named like
* "/dev/tty.MindSet-DevB-1".
*/
comPortName = "\\\\.\\" MWM_COM;
errCode = TG_Connect(connectionId,
comPortName,
TG_BAUD_57600,
TG_STREAM_PACKETS);
if (errCode < 0) {
MessageBox(hWnd, L"TG_Connect() failed", L"Error", MB_OK);
} else {
wchar_t buffer[100];
swprintf(buffer, 100, L"Connected to headset with %S", MWM_COM);
MessageBox(hWnd, buffer, L"Information", MB_OK);
bConnectedHeadset = true;
if ((threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&ThreadReadPacket, NULL, 0, &dwThreadId)) == NULL) {
MessageBox(hWnd, L"Failed to create packet reading thread", L"Error", MB_OK);
}
}
}
/*HWND hWnd1 = CreateWindowEx(0, szWindowClass, L"Child window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 320, 480, hWnd, NULL, hInst, NULL);
ShowWindow(hWnd1, SW_SHOWNORMAL);
UpdateWindow(hWnd1);*/
hInitBtn = CreateWindow(L"Button", L"Init", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_INIT_BUTTON, hInst, NULL);
hStartBtn = CreateWindow(L"Button", L"Start", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_START_BUTTON, hInst, NULL);
hStopBtn = CreateWindow(L"Button", L"Stop", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_STOP_BUTTON, hInst, NULL);
hBulkDataBtn = CreateWindow(L"Button", L"Data", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_BULK_DATA_BUTTON, hInst, NULL);
hStateText = CreateWindow(L"Static", L"State: ", WS_VISIBLE | WS_CHILD, 0, 0, STATE_TEXT_WIDTH, STATE_TEXT_HEIGHT, hWnd, (HMENU)IDD_STATE_TEXT, hInst, NULL);
hSignalQualityText = CreateWindow(L"Static", L"Signal Quality: ", WS_VISIBLE | WS_CHILD, 0, 0, SIGNAL_TEXT_WIDTH, SIGNAL_TEXT_HEIGHT, hWnd, (HMENU)IDD_SIGNAL_TEXT, hInst, NULL);
hVersionBtn = CreateWindow(L"Button", L"Version", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_INIT_BUTTON, hInst, NULL);
hOutputText = CreateWindow(L"Edit", L"", WS_VISIBLE | WS_CHILD | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 0, 0, 10, 10, hWnd, (HMENU)IDD_OUTPUT_TEXT, hInst, NULL);
hBPCheck = CreateWindow(L"Button", L"BP", WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_BP_CHECK, hInst, NULL);
hBlinkCheck = CreateWindow(L"Button", L"Blink", WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_AP_CHECK, hInst, NULL);
hAPCheck = CreateWindow(L"Button", L"AP", WS_VISIBLE | WS_DISABLED | WS_CHILD | BS_CHECKBOX, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_AP_CHECK, hInst, NULL);
hAttCheck = CreateWindow(L"Button", L"Att", WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_ATT_CHECK, hInst, NULL);
hMedCheck = CreateWindow(L"Button", L"Med", WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_MED_CHECK, hInst, NULL);
hMECheck = CreateWindow(L"Button", L"ME", WS_VISIBLE | WS_DISABLED | WS_CHILD | BS_CHECKBOX, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_ME_CHECK, hInst, NULL);
hME2Check = CreateWindow(L"Button", L"ME2", WS_VISIBLE | WS_DISABLED | WS_CHILD | BS_CHECKBOX, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_ME2_CHECK, hInst, NULL);
hFCheck = CreateWindow(L"Button", L"F", WS_VISIBLE | WS_DISABLED | WS_CHILD | BS_CHECKBOX, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_F_CHECK, hInst, NULL);
hF2Check = CreateWindow(L"Button", L"F2", WS_VISIBLE | WS_DISABLED | WS_CHILD | BS_CHECKBOX, 10, 10, BUTTON_WIDTH, BUTTON_HEIGHT, hWnd, (HMENU)IDD_F2_CHECK, hInst, NULL);
Button_Enable(hStartBtn, false);
Button_Enable(hStopBtn, false);
if (bConnectedHeadset == false) {
Button_Enable(hBulkDataBtn, true);
}
else {
Button_Enable(hBulkDataBtn, false);
}
// update UI components position
UIComponentsPositionUpdate(hWnd);
}
break;
case WM_USER_SETTEXT:
if ((HWND)wParam == hStateText) {
OutputLog((LPCWSTR)lParam);
}
SetWindowText((HWND)wParam, (LPCWSTR)lParam);
break;
case WM_ENABLE:
EnableWindow((HWND)wParam, (BOOL)lParam);
/*if ((HWND)wParam == hBulkDataBtn) {
if ((BOOL)lParam == true) {
(NSK_ALGO_StartAddr)(NS_FALSE);
eNSK_ALGO_RET ret = (NSK_ALGO_DataStreamAddr)(NSK_ALGO_DATA_TYPE_BULK_EEG, raw_data, (raw_data_count / 512) * 512);
}
}*/
break;
case WM_CTLCOLOREDIT:
{
HDC hdc = (HDC)wParam;
SetTextColor(hdc, RGB(0, 0, 0));
SetBkColor(hdc, RGB(200, 200, 200));
}
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDD_AP_CHECK:
case IDD_ATT_CHECK:
case IDD_MED_CHECK:
case IDD_ME_CHECK:
case IDD_ME2_CHECK:
case IDD_F_CHECK:
case IDD_F2_CHECK:
case IDD_BP_CHECK:
{
if (Button_GetCheck((HWND)lParam) == BST_CHECKED) {
Button_SetCheck((HWND)lParam, false);
} else {
Button_SetCheck((HWND)lParam, true);
}
}
break;
case IDD_INIT_BUTTON: // Pressed INIT button
case IDD_START_BUTTON: // Pressed START button
case IDD_STOP_BUTTON: // Pressed STOP button
case IDD_BULK_DATA_BUTTON: // Pressed DATA button
if (((HWND)lParam) && (HIWORD(wParam) == BN_CLICKED)) {
if ((HWND)lParam == hInitBtn) {
wchar_t ReadBuffer[1024] = { 0 };
char readBuf[1024] = { 0 };
GetCurrentDirectory(1024, ReadBuffer);
wcstombs_s(NULL, readBuf, ReadBuffer, 1024);
// check selected algorithms first
lSelectedAlgos = 0;
if (Button_GetCheck(hAttCheck)) {
lSelectedAlgos |= NSK_ALGO_TYPE_ATT;
}
if (Button_GetCheck(hMedCheck)) {
lSelectedAlgos |= NSK_ALGO_TYPE_MED;
}
if (Button_GetCheck(hBlinkCheck)) {
lSelectedAlgos |= NSK_ALGO_TYPE_BLINK;
}
if (Button_GetCheck(hBPCheck)) {
lSelectedAlgos |= NSK_ALGO_TYPE_BP;
}
if (lSelectedAlgos == 0) {
MessageBox(hWnd, L"Please select at least one algorithm", L"Error", MB_OK);
OutputLog(L"Please select at least one algorithm");
return 0;
}
if (bInited == false) {
eNSK_ALGO_RET ret = (NSK_ALGO_RegisterCallbackAddr)(&AlgoSdkCallback, hWnd);
ret = (NSK_ALGO_InitAddr)((eNSK_ALGO_TYPE)(lSelectedAlgos), readBuf);
if (NSK_ALGO_RET_SUCCESS == ret) {
//MessageBox(hWnd, L"Algo SDK inited successfully", L"Information", MB_OK);
OutputLog(L"Algo SDK inited successfully");
}
else {
wchar_t buffer[100];
swprintf(buffer, 100, L"Algo SDK inited failure [%d]", ret);
MessageBox(hWnd, buffer, L"Error", MB_OK);
OutputLog(buffer);
}
} else {
eNSK_ALGO_RET ret = (NSK_ALGO_UninitAddr)();
if (NSK_ALGO_RET_SUCCESS == ret) {
//MessageBox(hWnd, L"Algo SDK inited successfully", L"Information", MB_OK);
OutputLog(L"Algo SDK uninited successfully");
}
else {
wchar_t buffer[100];
swprintf(buffer, 100, L"Algo SDK uninit failure [%d]", ret);
MessageBox(hWnd, buffer, L"Error", MB_OK);
OutputLog(buffer);
}
}
} else if ((HWND)lParam == hStartBtn) {
eNSK_ALGO_RET ret;
wchar_t caption[20];
Button_GetText(hStartBtn, caption, 20);
if (lstrcmpW(caption, L"Start") == 0) {
ret = (NSK_ALGO_StartAddr)(NS_FALSE);
if (NSK_ALGO_RET_SUCCESS == ret) {
OutputLog(L"Algo SDK started successfully");
} else {
wchar_t buffer[100];
swprintf(buffer, 100, L"Algo SDK start failure [%d]", ret);
MessageBox(hWnd, buffer, L"Error", MB_OK);
OutputLog(buffer);
}
} else {
ret = (NSK_ALGO_PauseAddr)();
if (NSK_ALGO_RET_SUCCESS == ret) {
OutputLog(L"Algo SDK paused successfully");
}
else {
wchar_t buffer[100];
swprintf(buffer, 100, L"Algo SDK pause failure [%d]", ret);
MessageBox(hWnd, buffer, L"Error", MB_OK);
OutputLog(buffer);
}
}
} else if ((HWND)lParam == hStopBtn) {
eNSK_ALGO_RET ret = (NSK_ALGO_StopAddr)();
if (NSK_ALGO_RET_SUCCESS == ret) {
//MessageBox(hWnd, L"Algo SDK inited successfully", L"Information", MB_OK);
OutputLog(L"Algo SDK stopped successfully");
}
else {
wchar_t buffer[100];
swprintf(buffer, 100, L"Algo SDK stop failure [%d]", ret);
MessageBox(hWnd, buffer, L"Error", MB_OK);
OutputLog(buffer);
}
} else if ((HWND)lParam == hVersionBtn) {
wchar_t buffer[1024];
char *verStr = (NSK_ALGO_SdkVersionAddr)();
if (verStr != NULL) {
if (verStr[6] == 0x12) {
MessageBox(hWnd, L"Cracked version", L"Error", MB_OK);
}
swprintf(buffer, 1024, L"Comm SDK Ver: %d\r\nAlgo SDK Ver: %S\r\n", TG_GetVersion(), verStr);
if (lSelectedAlgos & NSK_ALGO_TYPE_ATT) {
swprintf(buffer, 1024, L"%sATT: %S\r\n", buffer, (NSK_ALGO_AlgoVersionAddr)(NSK_ALGO_TYPE_ATT));
}
if (lSelectedAlgos & NSK_ALGO_TYPE_MED) {
swprintf(buffer, 1024, L"%sMED: %S\r\n", buffer, (NSK_ALGO_AlgoVersionAddr)(NSK_ALGO_TYPE_MED));
}
if (lSelectedAlgos & NSK_ALGO_TYPE_BLINK) {
swprintf(buffer, 1024, L"%sBlink: %S\r\n", buffer, (NSK_ALGO_AlgoVersionAddr)(NSK_ALGO_TYPE_BLINK));
}
if (lSelectedAlgos & NSK_ALGO_TYPE_BP) {
swprintf(buffer, 1024, L"%sEEG Bandpower: %S\r\n", buffer, (NSK_ALGO_AlgoVersionAddr)(NSK_ALGO_TYPE_BP));
}
MessageBox(hWnd, buffer, L"Information", MB_OK);
}
}
else if ((HWND)lParam == hBulkDataBtn) {
// read data
HANDLE hFile;
DWORD dwBytesRead = 0;
wchar_t ReadBuffer[1024] = { 0 };
char readBuf[1024] = { 0 };
int index = 0;
Button_Enable(hBulkDataBtn, false);
if (raw_data) {
free(raw_data);
raw_data = NULL;
}
raw_data_count = 0;
GetCurrentDirectory(1024, ReadBuffer);
wcstombs_s(NULL, readBuf, ReadBuffer, 1024);
sprintf_s(readBuf, "%s\\%s", readBuf, EEG_RAW_DATA);
FILE *fp;
fopen_s(&fp, readBuf, "rb");
if (fp == NULL) {
MessageBox(hWnd, L"Failed to open file", L"Error", MB_OK);
Button_Enable(hBulkDataBtn, true);
return 0;
}
while (1) {
short raw_data_value = 0;
fgets(readBuf, 1024, fp);
raw_data_value = atoi(readBuf);
raw_data_count++;
if (feof(fp)) {
break;
}
}
fseek(fp, 0, SEEK_SET);
raw_data = (short*)malloc(sizeof(short)*raw_data_count);
if (raw_data == NULL) {
MessageBox(hWnd, L"Failed to allocate buffer for raw data", L"Error", MB_OK);
Button_Enable(hBulkDataBtn, true);
return 0;
}
while (1) {
fgets(readBuf, 1024, fp);
raw_data[index++] = atoi(readBuf);
if (feof(fp)) {
break;
}
}
fclose(fp);
eNSK_ALGO_RET ret = (NSK_ALGO_DataStreamAddr)(NSK_ALGO_DATA_TYPE_BULK_EEG, raw_data, (raw_data_count/512) * 512);
if (NSK_ALGO_RET_SUCCESS == ret) {
} else {
Button_Enable(hBulkDataBtn, true);
}
}
}
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
(NSK_ALGO_UninitAddr)();
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
/*MoveToEx(hdc, 60, 20, NULL);
LineTo(hdc, 60, 122);
LineTo(hdc, 264, 122);
LineTo(hdc, 60, 20);*/
EndPaint(hWnd, &ps);
}
break;
case WM_SIZING:
{
UIComponentsPositionUpdate(hWnd);
}
break;
case WM_DESTROY:
if (connectionId >= 0) {
TG_Disconnect(connectionId); // disconnect test
/* Clean up */
TG_FreeConnection(connectionId);
connectionId = -1;
}
if (threadHandle != NULL) {
TerminateThread(threadHandle, 0);
threadHandle = NULL;
}
DestroyWindow(hInitBtn);
DestroyWindow(hStartBtn);
DestroyWindow(hStopBtn);
DestroyWindow(hAttCheck);
DestroyWindow(hMedCheck);
DestroyWindow(hAPCheck);
DestroyWindow(hBlinkCheck);
DestroyWindow(hBPCheck);
DestroyWindow(hMECheck);
DestroyWindow(hME2Check);
DestroyWindow(hFCheck);
DestroyWindow(hF2Check);
DestroyWindow(hBulkDataBtn);
DestroyWindow(hStateText);
DestroyWindow(hSignalQualityText);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
Comments