Search

2012年12月18日 星期二

wxWidgets Connect Arduino(Windows)

    跟之前的wxWidgets Connect Arduino(Linux)一樣,只不過變成Windows版,因為只用Serial Port所以Enumeration就直接一個一個Create,如果改天要用其他如USB的Device寫成Driver會比較好處理,最後非同步有開/Od要處理WriteFile的ERROR_IO_PENDING而開/O2不用,另外我是在Windows 7 x64測試。




wxarduino.h


#ifndef __WX_ARDUINO__
#define __WX_ARDUINO__

#include <wx/wx.h>

#include "serialport.h"
#include "connectargsdlg.h"

class App:public wxApp
{
   public:
      bool OnInit();
};

class Frame:public wxFrame
{
public:
Frame(const wxString&);

void OnSendData(wxTimerEvent&);
void OnConnectDevice(wxCommandEvent&);
void OnReleaseDevice(wxCommandEvent&);
void OnExit(wxCommandEvent&);

private:
enum{
ID_SEND_DATA = 100,
ID_CONNECT_DEVICE,
ID_RELEASE_DEVICE
};

static const unsigned int MAX = 2;

wxMenu *device_path;

wxTimer timer;

SerialPort serial;

wxSlider *servos[MAX];
wxBoxSizer *box[MAX];
wxStaticText *servos_text[MAX];
unsigned char data[MAX];

DECLARE_EVENT_TABLE()
};

#endif


wxarduino.cpp


#include "wxarduino.h"

DECLARE_APP(App)
IMPLEMENT_APP(App)

bool App::OnInit()
{
   Frame *frame = new Frame(wxT("wxArduino"));

   frame->Show(true);

   return true;
}

BEGIN_EVENT_TABLE(Frame,wxFrame)
   EVT_MENU(wxID_EXIT,Frame::OnExit)
   EVT_MENU(ID_CONNECT_DEVICE,Frame::OnConnectDevice)
   EVT_MENU(ID_RELEASE_DEVICE,Frame::OnReleaseDevice)
   EVT_TIMER(ID_SEND_DATA,Frame::OnSendData)
END_EVENT_TABLE()

Frame::Frame(const wxString &title):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,wxDefaultSize,wxMINIMIZE_BOX | wxCLOSE_BOX | wxCAPTION | wxSYSTEM_MENU),timer(this,ID_SEND_DATA),serial()
{
   timer.Stop();

   wxMenu *file = new wxMenu;
   file->Append(wxID_EXIT,wxT("E&xit\tAlt-e"),wxT("Exit"));
   wxMenu *tools = new wxMenu;
   tools->Append(ID_CONNECT_DEVICE,wxT("C&onnect Device\tAlt-c"),wxT("Connect Device"));
   tools->Append(ID_RELEASE_DEVICE,wxT("R&elease Device\tAlt-r"),wxT("Release Device"));

   wxMenuBar *bar = new wxMenuBar;
   bar->Append(file,wxT("File"));
   bar->Append(tools,wxT("Tools"));
   SetMenuBar(bar);

   wxBoxSizer *top = new wxBoxSizer(wxVERTICAL);
   this->SetSizer(top);

   for(int i = 0;i < MAX;++i){
      box[i] = new wxBoxSizer(wxHORIZONTAL);
      top->Add(box[i],0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

      wxString text;
 text.Printf(wxT("Servo %d:"),i + 1);
      servos_text[i] = new wxStaticText(this,wxID_STATIC,text,wxDefaultPosition,wxDefaultSize,0);
      box[i]->Add(servos_text[i],0,wxALIGN_CENTER_HORIZONTAL |  wxALIGN_CENTER_VERTICAL,5);

      servos[i] = new wxSlider(this,wxID_ANY,90,0,180,wxDefaultPosition,wxSize(200,-1),wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS);
      box[i]->Add(servos[i],0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);
   }

   CreateStatusBar(2);
   SetStatusText(wxT("wxArduino"));

   top->Fit(this);
   top->SetSizeHints(this);
}

void Frame::OnSendData(wxTimerEvent &event)
{
   for(int i = 0;i < MAX;++i){
      data[i] = servos[i]->GetValue();
   }
   serial.Write(data,MAX);
}

void Frame::OnConnectDevice(wxCommandEvent &event)
{
ConnectArgsDialog dlg(this,wxID_ANY,wxT("Connect"),wxDefaultPosition,wxDefaultSize,wxDEFAULT_DIALOG_STYLE);

    if(dlg.ShowModal() == wxID_OK){
serial.Open(dlg.GetDevicePath(),dlg.GetBaudRate());

timer.Start(30);
    }
}

void Frame::OnReleaseDevice(wxCommandEvent &event)
{
   serial.Close();
   timer.Stop();
}

void Frame::OnExit(wxCommandEvent &event)
{
   timer.Stop();
   Close();
}




connectargsalg.h


#ifndef __CONNECT_ARGS_DIALOG__
#define __CONNECT_ARGS_DIALOG__

#include <wx/wx.h>
#include <windows.h>

class ConnectArgsDialog:public wxDialog
{
public:
ConnectArgsDialog();

ConnectArgsDialog(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxString &caption = wxT("Connect Args"),
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = wxCAPTION | wxRESIZE_BORDER | wxSYSTEM_MENU);

bool Create(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxString &caption = wxT("Connect Args"),
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = wxCAPTION | wxRESIZE_BORDER | wxSYSTEM_MENU);

void Init();
void CreateControls();

bool TransferDataToWindow();
bool TransferDataFromWindow();

wxString GetDevicePath(){return device_path->GetString(device_path->GetCurrentSelection());}
long GetBaudRate(){return wxAtoi(baud_rate->GetString(baud_rate->GetCurrentSelection()));}

private:
wxChoice *device_path;
wxChoice *baud_rate;

DECLARE_CLASS(ConnectArgsDialog)
};

#endif


connectargsdlg.cpp


#include "connectargsdlg.h"

IMPLEMENT_CLASS(ConnectArgsDialog,wxDialog)

ConnectArgsDialog::ConnectArgsDialog()
{
   Init();
}

ConnectArgsDialog::ConnectArgsDialog(wxWindow *parent,wxWindowID id,const wxString &caption,const wxPoint &pos,const wxSize &size,long style)
{
   Create(parent,id,caption,pos,size,style);
   Init();
}

inline void ConnectArgsDialog::Init()
{
}

bool ConnectArgsDialog::Create(wxWindow *parent,wxWindowID id,const wxString &caption,const wxPoint &pos,const wxSize &size,long style)
{
   SetExtraStyle(wxWS_EX_BLOCK_EVENTS | wxDIALOG_EX_CONTEXTHELP);

   if(!wxDialog::Create(parent,id,caption,pos,size,style)){
      return false;
   }

   CreateControls();

   GetSizer()->Fit(this);
   GetSizer()->SetSizeHints(this);

   Center();

   return true;
}

void ConnectArgsDialog::CreateControls()
{
   wxBoxSizer *top = new wxBoxSizer(wxVERTICAL);
   this->SetSizer(top);

   wxBoxSizer *box = new wxBoxSizer(wxHORIZONTAL);
   top->Add(box,0,wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,5);

   wxArrayString paths;

   for(int i = 1;i <= 10;++i){
  wxString com;
  com.Printf(wxT("COM%d"),i);
  HANDLE handle = CreateFile(com.wc_str(),GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
  if(handle != INVALID_HANDLE_VALUE){
  paths.Add(com);
  CloseHandle(handle);
  }
   }

   device_path = new wxChoice(this,wxID_ANY,wxDefaultPosition,wxDefaultSize,paths);
   box->Add(device_path,0,wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,5);

   wxArrayString speed;
   speed.Add(wxT("300"));
   speed.Add(wxT("1200"));
   speed.Add(wxT("2400"));
   speed.Add(wxT("4800"));
   speed.Add(wxT("9600"));
   speed.Add(wxT("19200"));
   speed.Add(wxT("38400"));
   speed.Add(wxT("57600"));
   speed.Add(wxT("115200"));

   baud_rate = new wxChoice(this,wxID_ANY,wxDefaultPosition,wxDefaultSize,speed);
   box->Add(baud_rate,0,wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,5);

   wxBoxSizer *ResetOkCancelBox = new wxBoxSizer(wxHORIZONTAL);
   top->Add(ResetOkCancelBox,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

   wxButton *ok = new wxButton(this,wxID_OK,wxT("&Ok"),wxDefaultPosition,wxDefaultSize,0);
   ResetOkCancelBox->Add(ok,0,wxALIGN_CENTER_VERTICAL | wxALL,5);

   wxButton *cancel = new wxButton(this,wxID_CANCEL,wxT("&Cancel"),wxDefaultPosition,wxDefaultSize,0);
   ResetOkCancelBox->Add(cancel,0,wxALIGN_CENTER_VERTICAL | wxALL,5);
}

bool ConnectArgsDialog::TransferDataToWindow()
{
   return true;
}

bool ConnectArgsDialog::TransferDataFromWindow()
{
   return true;
}

serialport.h


#ifndef __SERIAL_PORT__
#define __SERIAL_PORT__

#include <wx/wx.h>

#include <windows.h>

class SerialPort
{
public:
SerialPort();
~SerialPort();
bool Open(const wxString,const DWORD);
void Close();
void Write(unsigned char*,DWORD);
void Read(unsigned  char*,DWORD);

private:
HANDLE com;
DCB dcb;
COMMTIMEOUTS timeouts;
OVERLAPPED overlapped;
};

#endif

serialport.cpp


#include "serialport.h"

SerialPort::SerialPort():dcb(),timeouts(),overlapped()
{
com = NULL;
}

SerialPort::~SerialPort()
{
   Close();
}

bool SerialPort::Open(const wxString path,const DWORD baud_rate)
{
Close();

com = CreateFile(path.wc_str(),GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);

if(com == INVALID_HANDLE_VALUE){
Close();
return false;
}

memset(&dcb,0,sizeof(dcb));
wxString def;
def.Printf(wxT("%d,n,8,1"),baud_rate);
BuildCommDCB(def.wc_str(),&dcb);

if(!SetCommState(com,&dcb)){
Close();
return false;
}

memset(&timeouts,0,sizeof(timeouts));
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;

if(!SetCommTimeouts(com,&timeouts)){
Close();
return false;
}

memset(&overlapped,0,sizeof(overlapped));
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
overlapped.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

return true;
}

void SerialPort::Close()
{
if(com){
CloseHandle(com);
com = NULL;
}
}

void SerialPort::Write(unsigned char *data,DWORD length)
{
if(com){
PurgeComm(com, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
WriteFile(com,data,length,NULL,&overlapped);
}
}

void SerialPort::Read(unsigned char *data,DWORD length)
{
if(com){
PurgeComm(com, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
ReadFile(com,data,length,NULL,&overlapped);
}
}

servo.pde


#include <Servo.h>

const unsigned int MAX = 2;

Servo servos[MAX];

void setup() {            
  Serial.begin(9600);

  for(int i = 0;i < MAX;++i){
    servos[i].attach(i + 3);
    servos[i].write(90);
  }
}

void loop() {

  for(int i = 0;Serial.available() > 0;++i){
    delay(1);    //速度小於1ms接收資料會錯誤
    int angle = Serial.read();
    servos[i].write(angle);
  }
}


沒有留言:

張貼留言