telldus/telldus-core/service/TellStick.cpp
2010-10-13 09:22:49 +00:00

384 lines
7.8 KiB
C++

//
// C++ Implementation: TellStick
//
// Description:
//
//
// Author: Micke Prag <micke.prag@telldus.se>, (C) 2009
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "TellStick.h"
#include "../client/telldus-core.h"
#include <string.h>
#include <stdlib.h>
class TellStick::TellStickDescriptor {
public:
bool found;
std::string serial;
int vid, pid;
};
class TellStick::PrivateData {
public:
bool open;
TellStickHandle ftHandle;
TellStickDescriptor descriptor;
};
TellStick::TellStick( const TellStickDescriptor &td ) {
d = new PrivateData;
d->open = false;
d->descriptor = td;
#ifdef LIBFTDI
ftdi_init(&d->ftHandle);
int ret = ftdi_usb_open_desc(&d->ftHandle, td.vid, td.pid, NULL, td.serial.c_str());
if (ret < 0) {
ftdi_deinit(&d->ftHandle);
return;
}
d->open = true;
ftdi_usb_reset( &d->ftHandle );
ftdi_disable_bitbang( &d->ftHandle );
#else
char *tempSerial = new char[td.serial.size()+1];
#ifdef _WINDOWS
strcpy_s(tempSerial, td.serial.size()+1, td.serial.c_str());
#else
strcpy(tempSerial, td.serial.c_str());
FT_SetVIDPID(td.vid, td.pid);
#endif
FT_STATUS ftStatus = FT_OpenEx(tempSerial, FT_OPEN_BY_SERIAL_NUMBER, &d->ftHandle);
delete tempSerial;
if (ftStatus == FT_OK) {
d->open = true;
FT_SetFlowControl(d->ftHandle, FT_FLOW_NONE, 0, 0);
FT_SetTimeouts(d->ftHandle,5000,0);
}
#endif
if (d->open) {
setBaud(4800);
}
}
TellStick::~TellStick() {
if (d->open) {
#ifdef LIBFTDI
ftdi_usb_close(&d->ftHandle);
ftdi_deinit(&d->ftHandle);
#else
FT_Close(d->ftHandle);
#endif
}
delete d;
}
int TellStick::vid() const {
return d->descriptor.vid;
}
int TellStick::pid() const {
return d->descriptor.pid;
}
std::string TellStick::serial() const {
return d->descriptor.serial;
}
bool TellStick::open() const {
return d->open;
}
TellStick *TellStick::findFirstDevice(int vid, int pid) {
TellStick *tellstick = 0;
if (vid == 0 && pid == 0) {
tellstick = findFirstDevice(0x1781, 0x0C30);
if (tellstick) {
return tellstick;
}
#ifdef TELLSTICK_DUO
tellstick = findFirstDevice(0x1781, 0x0C31);
#endif
return tellstick;
}
TellStickDescriptor d = findByVIDPID(vid, pid);
if (d.found) {
#ifdef TELLSTICK_DUO
if (pid == 0x0C31) {
return new TellStickDuo(d);
}
#endif
return new TellStick(d);
}
return 0;
}
TellStick *TellStick::loadBy(int vid, int pid, const std::string &serial) {
if (vid != 0x1781) {
return 0;
}
TellStick *tellstick = 0;
if (serial.length() == 0) {
tellstick = TellStick::findFirstDevice();
} else {
TellStickDescriptor d;
d.vid = vid;
d.pid = pid;
d.serial = serial;
if (pid == 0x0C30) {
tellstick = new TellStick(d);
#ifdef TELLSTICK_DUO
} else if (pid == 0x0C31) {
tellstick = new TellStickDuo(d);
#endif
}
}
if (!tellstick) {
return 0;
}
if (tellstick->open()) {
return tellstick;
}
delete tellstick;
return 0;
}
TellStick::TellStickDescriptor TellStick::findByVIDPID( int vid, int pid ) {
TellStickDescriptor retval;
retval.found = false;
retval.vid = vid;
retval.pid = pid;
#ifdef LIBFTDI
ftdi_context ftdic;
struct ftdi_device_list *devlist, *curdev;
char serialBuffer[10];
ftdi_init(&ftdic);
int ret = ftdi_usb_find_all(&ftdic, &devlist, vid, pid);
if (ret > 0) {
for (curdev = devlist; curdev != NULL; curdev = curdev->next) {
ret = ftdi_usb_get_strings(&ftdic, curdev->dev, NULL, 0, NULL, 0, serialBuffer, 10);
if (ret != 0) {
continue;
}
retval.serial = serialBuffer;
break;
}
retval.found = true;
}
ftdi_list_free(&devlist);
ftdi_deinit(&ftdic);
#else
FT_HANDLE fthHandle = 0;
FT_STATUS ftStatus = FT_OK;
try{
DWORD dwNumberOfDevices = 0;
#ifndef _WINDOWS
FT_SetVIDPID(vid, pid);
#endif
ftStatus = FT_CreateDeviceInfoList(&dwNumberOfDevices);
if (ftStatus == FT_OK) {
for (int i = 0; i < (int)dwNumberOfDevices; i++) {
FT_PROGRAM_DATA pData;
char ManufacturerBuf[32];
char ManufacturerIdBuf[16];
char DescriptionBuf[64];
char SerialNumberBuf[16];
pData.Signature1 = 0x00000000;
pData.Signature2 = 0xffffffff;
pData.Version = 0x00000002; // EEPROM structure with FT232R extensions
pData.Manufacturer = ManufacturerBuf;
pData.ManufacturerId = ManufacturerIdBuf;
pData.Description = DescriptionBuf;
pData.SerialNumber = SerialNumberBuf;
ftStatus = FT_Open(i, &fthHandle);
ftStatus = FT_EE_Read(fthHandle, &pData);
if(ftStatus == FT_OK){
if(pData.VendorId == vid && pData.ProductId == pid){
ftStatus = FT_Close(fthHandle);
retval.found = true;
retval.serial = pData.SerialNumber;
break;
}
}
ftStatus = FT_Close(fthHandle);
}
}
}
catch(...){
throw;
}
#endif
return retval;
}
int TellStick::firmwareVersion() {
return 1;
}
int TellStick::send(const std::string & strMessage) {
if (!d->open) {
return TELLSTICK_ERROR_NOT_FOUND;
}
bool c = true;
#ifdef LIBFTDI
unsigned char *tempMessage = new unsigned char[strMessage.size()];
memcpy(tempMessage, strMessage.c_str(), strMessage.size());
int ret;
ret = ftdi_write_data( &d->ftHandle, tempMessage, strMessage.length() ) ;
if(ret < 0) {
c = false;
} else if(ret != strMessage.length()) {
fprintf(stderr, "wierd send length? retval %i instead of %d\n",
ret, (int)strMessage.length());
}
delete[] tempMessage;
int retrycnt = 500;
unsigned char in;
while(c && --retrycnt) {
ret = ftdi_read_data( &d->ftHandle, &in, 1);
if (ret > 0) {
if (in == '\n') {
break;
}
} else if(ret == 0) { // No data available
usleep(100);
} else { //Error
c = false;
}
}
if (!retrycnt) {
c = false;
}
#else
char *tempMessage = (char *)malloc(sizeof(char) * (strMessage.size()+1));
#ifdef _WINDOWS
strcpy_s(tempMessage, strMessage.size()+1, strMessage.c_str());
#else
strcpy(tempMessage, strMessage.c_str());
#endif
ULONG bytesWritten, bytesRead;
char in;
FT_STATUS ftStatus;
ftStatus = FT_Write(d->ftHandle, tempMessage, (DWORD)strMessage.length(), &bytesWritten);
free(tempMessage);
while(c) {
ftStatus = FT_Read(d->ftHandle,&in,1,&bytesRead);
if (ftStatus == FT_OK) {
if (bytesRead == 1) {
if (in == '\n') {
break;
}
} else { //Timeout
c = false;
}
} else { //Error
c = false;
}
}
#endif
if (!c) {
return TELLSTICK_ERROR_COMMUNICATION;
}
return TELLSTICK_SUCCESS;
}
void TellStick::setBaud(int baud) {
#ifdef LIBFTDI
int ret = ftdi_set_baudrate(&d->ftHandle, baud);
if(ret != 0) {
fprintf(stderr, "set Baud failed, retval %i\n", ret);
}
#else
FT_SetBaudRate(d->ftHandle, baud);
#endif
}
TellStickHandle TellStick::handle() const {
return d->ftHandle;
}
bool TellStick::stillConnected() const {
std::string serial = this->serial();
#ifdef LIBFTDI
ftdi_context ftdic;
struct ftdi_device_list *devlist, *curdev;
char serialBuffer[10];
ftdi_init(&ftdic);
bool found = false;
int ret = ftdi_usb_find_all(&ftdic, &devlist, this->vid(), this->pid());
if (ret > 0) {
for (curdev = devlist; curdev != NULL; curdev = curdev->next) {
ret = ftdi_usb_get_strings(&ftdic, curdev->dev, NULL, 0, NULL, 0, serialBuffer, 10);
if (ret != 0) {
continue;
}
if (serial.compare(serialBuffer) == 0) {
found = true;
break;
}
}
}
ftdi_list_free(&devlist);
ftdi_deinit(&ftdic);
return found;
#else
FT_STATUS ftStatus;
DWORD numDevs;
// create the device information list
ftStatus = FT_CreateDeviceInfoList(&numDevs);
if (ftStatus != FT_OK) {
return false;
}
if (numDevs <= 0) {
return false;
}
for (int i = 0; i < (int)numDevs; i++) {
FT_HANDLE ftHandleTemp;
DWORD flags;
DWORD id;
DWORD type;
DWORD locId;
char serialNumber[16];
char description[64];
// get information for device 0
ftStatus = FT_GetDeviceInfoDetail(i, &flags, &type, &id, &locId, serialNumber, description, &ftHandleTemp);
if (ftStatus != FT_OK) {
continue;
}
if (serial.compare(serialNumber) == 0) {
return true;
}
}
return false;
#endif
}