diff --git a/src/add-ons/input_server/devices/Jamfile b/src/add-ons/input_server/devices/Jamfile index bfd7111a86..e16bf9d77f 100644 --- a/src/add-ons/input_server/devices/Jamfile +++ b/src/add-ons/input_server/devices/Jamfile @@ -1,5 +1,6 @@ SubDir HAIKU_TOP src add-ons input_server devices ; +SubInclude HAIKU_TOP src add-ons input_server devices easypen ; SubInclude HAIKU_TOP src add-ons input_server devices keyboard ; SubInclude HAIKU_TOP src add-ons input_server devices mouse ; #SubInclude HAIKU_TOP src add-ons input_server devices serial_mouse ; diff --git a/src/add-ons/input_server/devices/easypen/EasyPenInputDevice.cpp b/src/add-ons/input_server/devices/easypen/EasyPenInputDevice.cpp new file mode 100644 index 0000000000..2f0a97c764 --- /dev/null +++ b/src/add-ons/input_server/devices/easypen/EasyPenInputDevice.cpp @@ -0,0 +1,343 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Jérôme Duval + * + * References: + * Google search "technic doc genius" , http://www.bebits.com/app/2152 + */ + +#include +#include +#include + +#include +#include +#include + +#include "EasyPenInputDevice.h" +#include "kb_mouse_driver.h" + +/* +IN ABSOLUTE MODE (MM Series) + + Least Most + + Bytes Bit to Significant Significant Bit to + +Transmitted Start Bit Bit Stop + + 0 1 2 3 4 5 6 7 8 + +----------- ----- --------------------------------------------- ------ + +1st Byte 0 Fa Fb Fc Sy Sx T PR PH P 1 + +2nd Byte 0 X0 X1 X2 X3 X4 X5 X6 0 P 1 + +3rd Byte 0 X7 X8 X9 X10 X11 X12 X13 0 P 1 + +4th Byte 0 Y0 Y1 Y2 Y3 Y4 Y5 Y6 0 P 1 + +5th Byte 0 Y7 Y8 Y9 Y10 Y11 Y12 Y13 0 P 1 + +*/ + +#if DEBUG + inline void LOG(const char *fmt, ...) { char buf[1024]; va_list ap; va_start(ap, fmt); vsprintf(buf, fmt, ap); va_end(ap); \ + fputs(buf, EasyPenInputDevice::sLogFile); fflush(EasyPenInputDevice::sLogFile); } + #define LOG_ERR(text...) LOG(text) +FILE *EasyPenInputDevice::sLogFile = NULL; +#else + #define LOG(text...) + #define LOG_ERR(text...) fprintf(stderr, text) +#endif + +#define CALLED() LOG("%s\n", __PRETTY_FUNCTION__) + +#ifndef B_FIRST_REAL_TIME_PRIORITY +# define B_FIRST_REAL_TIME_PRIORITY B_REAL_TIME_DISPLAY_PRIORITY +#endif +const static uint32 kTabletThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; + +struct tablet_device { + tablet_device(BSerialPort *port); + ~tablet_device(); + + input_device_ref device_ref; + thread_id device_watcher; + bool active; + BSerialPort *serial; + EasyPenInputDevice *owner; +}; + + +extern "C" +BInputServerDevice * +instantiate_input_device() +{ + return new EasyPenInputDevice(); +} + + +EasyPenInputDevice::EasyPenInputDevice() +{ +#if DEBUG + sLogFile = fopen("/var/log/easypen_device_log.log", "a"); +#endif +} + + +EasyPenInputDevice::~EasyPenInputDevice() +{ + CALLED(); + for (int32 i = 0; i < fDevices.CountItems(); i++) + delete (tablet_device *)fDevices.ItemAt(i); + +#if DEBUG + fclose(sLogFile); +#endif +} + + +status_t +EasyPenInputDevice::InitCheck() +{ + CALLED(); + + BSerialPort *serial = new BSerialPort(); + int count = serial->CountDevices(); + char devName[B_OS_NAME_LENGTH]; + char byte; + + for (int i=0; iGetDeviceName(i, devName); + serial->SetDataRate(B_9600_BPS); + serial->SetDataBits(B_DATA_BITS_8); + serial->SetStopBits(B_STOP_BITS_1); + serial->SetParityMode(B_ODD_PARITY); + serial->SetFlowControl(B_HARDWARE_CONTROL+B_SOFTWARE_CONTROL); + serial->SetBlocking(true); + serial->SetTimeout(800000); + + if (serial->Open(devName) < B_OK) { + LOG("Fail to open %s\n", devName); + continue; + } + snooze(250000); + serial->Write("z9", 2); // 8 data bits,odd parity z 9 + serial->Write((char)NULL, 1); // Reset NUL + serial->Write("DP", 2); // mode command D trigger command P + snooze(250000); + serial->ClearInput(); + serial->Write("twP", 3); // Self-Test, Send Test Results, trigger command P + serial->Read(&byte, 1); + if ((byte & 0xf7) != 0x87) { + LOG("Self test failed for %s %x\n", devName, byte & 0xf7); + continue; + } + tablet_device *device = new tablet_device(serial); + device->owner = this; + + input_device_ref *devices[2]; + devices[0] = &device->device_ref; + devices[1] = NULL; + + fDevices.AddItem(device); + RegisterDevices(devices); + + serial = new BSerialPort(); + } + + delete serial; + + LOG("Found %ld devices\n", fDevices.CountItems()); + + get_click_speed(&fClickSpeed); + + return fDevices.CountItems() > 0 ? B_OK : B_ERROR; +} + + +status_t +EasyPenInputDevice::Start(const char *name, void *cookie) +{ + tablet_device *device = (tablet_device *)cookie; + + LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); + + char threadName[B_OS_NAME_LENGTH]; + snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", name); + + device->active = true; + device->device_watcher = spawn_thread(DeviceWatcher, threadName, + kTabletThreadPriority, device); + + if (device->device_watcher < B_OK) + return device->device_watcher; + resume_thread(device->device_watcher); + + return B_OK; +} + + +status_t +EasyPenInputDevice::Stop(const char *name, void *cookie) +{ + tablet_device *device = (tablet_device *)cookie; + + LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); + + device->active = false; + if (device->device_watcher >= 0) { + suspend_thread(device->device_watcher); + resume_thread(device->device_watcher); + status_t dummy; + wait_for_thread(device->device_watcher, &dummy); + } + + return B_OK; +} + + +status_t +EasyPenInputDevice::Control(const char *name, void *cookie, + uint32 command, BMessage *message) +{ + LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); + + if (command == B_CLICK_SPEED_CHANGED) + get_click_speed(&fClickSpeed); + + return B_OK; +} + + +int32 +EasyPenInputDevice::DeviceWatcher(void *arg) +{ + tablet_device *dev = (tablet_device *)arg; + EasyPenInputDevice *owner = dev->owner; + + tablet_movement movements; + tablet_movement old_movements; + BMessage *message; + uint8 byte; + uint8 bytes[4]; + bigtime_t lastClickTimeStamp = 0LL; + + memset(&movements, 0, sizeof(movements)); + memset(&old_movements, 0, sizeof(old_movements)); + + dev->serial->Write(":@FRb", 5); + + while (dev->active) { + byte = 0; + while(!byte) + dev->serial->Read(&byte, 1); + if (byte & 0x40 || !(byte & 0x80)) { // 7th bit on or 8th bit off + snooze(10000); // this is a realtime thread, and something is wrong... + continue; + } + + if (dev->serial->Read(bytes, 4) != 4) + continue; + + if (*(uint32*)bytes & 0x80808080) + continue; + + movements.buttons = byte & 0x7; + movements.timestamp = system_time(); + movements.xpos = (bytes[1] << 7) | bytes[0]; + movements.ypos = (bytes[3] << 7) | bytes[2]; + + uint32 buttons = old_movements.buttons ^ movements.buttons; + + LOG("%s: buttons: 0x%lx, x: %f, y: %f, clicks:%ld, wheel_x:%ld, wheel_y:%ld\n", dev->device_ref.name, movements.buttons, + movements.xpos, movements.ypos, movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta); + + movements.xpos /= 1950.0; + movements.ypos /= 1500.0; + + LOG("%s: x: %f, y: %f, \n", dev->device_ref.name, movements.xpos, movements.ypos); + + if (buttons != 0) { + message = new BMessage(B_MOUSE_UP); + if ((buttons & movements.buttons) > 0) { + message->what = B_MOUSE_DOWN; + if(lastClickTimeStamp + owner->fClickSpeed <= movements.timestamp) + movements.clicks = 1; + else + movements.clicks++; + lastClickTimeStamp = movements.timestamp; + message->AddInt32("clicks", movements.clicks); + LOG("B_MOUSE_DOWN\n"); + } else { + LOG("B_MOUSE_UP\n"); + } + + message->AddInt64("when", movements.timestamp); + message->AddInt32("buttons", movements.buttons); + message->AddFloat("x", movements.xpos); + message->AddFloat("y", movements.ypos); + owner->EnqueueMessage(message); + } + + if (movements.xpos != 0.0 || movements.ypos != 0.0) { + message = new BMessage(B_MOUSE_MOVED); + if (message) { + message->AddInt64("when", movements.timestamp); + message->AddInt32("buttons", movements.buttons); + message->AddFloat("x", movements.xpos); + message->AddFloat("y", movements.ypos); + message->AddFloat("be:tablet_x", movements.xpos); + message->AddFloat("be:tablet_y", movements.ypos); + message->AddFloat("be:tablet_pressure", movements.pressure); + message->AddInt32("be:tablet_eraser", movements.eraser); + if (movements.tilt_x != 0.0 || movements.tilt_y != 0.0) { + message->AddFloat("be:tablet_tilt_x", movements.tilt_x); + message->AddFloat("be:tablet_tilt_y", movements.tilt_y); + } + + owner->EnqueueMessage(message); + } + } + + if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) { + message = new BMessage(B_MOUSE_WHEEL_CHANGED); + if (message) { + message->AddInt64("when", movements.timestamp); + message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta); + message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta); + + owner->EnqueueMessage(message); + } + } + + old_movements = movements; + + } + + return 0; +} + + +// tablet_device +tablet_device::tablet_device(BSerialPort *port) +{ + serial = port; + device_watcher = -1; + active = false; + device_ref.name = strdup("Genius EasyPen"); + device_ref.type = B_POINTING_DEVICE; + device_ref.cookie = this; +}; + + +tablet_device::~tablet_device() +{ + free(device_ref.name); +} + diff --git a/src/add-ons/input_server/devices/easypen/EasyPenInputDevice.h b/src/add-ons/input_server/devices/easypen/EasyPenInputDevice.h new file mode 100644 index 0000000000..563c6c1e5b --- /dev/null +++ b/src/add-ons/input_server/devices/easypen/EasyPenInputDevice.h @@ -0,0 +1,47 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Jérôme Duval + * + * References: + * Google search "technic doc genius" , http://www.bebits.com/app/2152 + */ + +#ifndef __EASYPENINPUTDEVICE_H +#define __EASYPENINPUTDEVICE_H + +#include +#include +#include + +struct tablet_device; + +class EasyPenInputDevice : public BInputServerDevice { +public: + EasyPenInputDevice(); + ~EasyPenInputDevice(); + + virtual status_t InitCheck(); + + virtual status_t Start(const char *name, void *cookie); + virtual status_t Stop(const char *name, void *cookie); + + virtual status_t Control(const char *name, void *cookie, + uint32 command, BMessage *message); +private: + static int32 DeviceWatcher(void *arg); + + BList fDevices; + bigtime_t fClickSpeed; +#ifdef DEBUG +public: + static FILE *sLogFile; +#endif +}; + +extern "C" BInputServerDevice *instantiate_input_device(); + +#endif + diff --git a/src/add-ons/input_server/devices/easypen/Jamfile b/src/add-ons/input_server/devices/easypen/Jamfile new file mode 100644 index 0000000000..87bd29b45d --- /dev/null +++ b/src/add-ons/input_server/devices/easypen/Jamfile @@ -0,0 +1,11 @@ +SubDir HAIKU_TOP src add-ons input_server devices easypen ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders input ; + +Addon easypen : input_server/devices : + EasyPenInputDevice.cpp + : false + : be device input_server ; +