Merge branch 'master' into ticket96
Conflicts: telldus-gui/Plugins/Sensors/main.qml telldus-gui/Plugins/Sensors/sensor.cpp
This commit is contained in:
commit
bdb766e7cf
108 changed files with 3128 additions and 678 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1 +1,6 @@
|
||||||
build/
|
build/
|
||||||
|
qtcreator-build/
|
||||||
|
Doxyfile
|
||||||
|
html/
|
||||||
|
latex/
|
||||||
|
CMakeLists.txt.user
|
||||||
|
|
|
@ -187,10 +187,54 @@
|
||||||
* tdReleaseString(name);
|
* tdReleaseString(name);
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
|
* \subsection sec_bu_sensors Sensors
|
||||||
|
*
|
||||||
|
* Retrieving sensor values can be done in two ways. Either by a polling
|
||||||
|
* interface or by callbacks. The client application can implement one or both
|
||||||
|
* of these interfaces. For callbacks, read more under \ref sec_events.
|
||||||
|
*
|
||||||
|
* Each of the sensors can have one or several value types. Currently only
|
||||||
|
* temperature and humidity are implemented.
|
||||||
|
*
|
||||||
|
* There is no API to add, remove or edit sensors. Each sensor that
|
||||||
|
* TellStick Duo has got any data from is added to an internal list. It is up to
|
||||||
|
* the client application to filter and only show the sensors your are
|
||||||
|
* interested in.
|
||||||
|
*
|
||||||
|
* To iterate over the list of sensors, call tdSensor() repeatedly as long as it
|
||||||
|
* returns \c TELLSTICK_SUCCESS. The parameters \c protocol, \c model,
|
||||||
|
* \c sensorId, and \c dataTypes are sent by reference and will be filled with
|
||||||
|
* the values.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* \code
|
||||||
|
* char protocol[DATA_LENGTH], model[DATA_LENGTH];
|
||||||
|
* int sensorId = 0, dataTypes = 0;
|
||||||
|
* while(tdSensor(protocol, DATA_LENGTH, model, DATA_LENGTH, &sensorId, &dataTypes) == TELLSTICK_SUCCESS) {
|
||||||
|
* //Print the sensor
|
||||||
|
* printf("%s,\t%s,\t%i\n", protocol, model, sensorId);
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* The type of sensor values the sensor supports are stored as flags in the
|
||||||
|
* parameter \c sensorId. Call tdSensorValue() for each type.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* \code
|
||||||
|
* char value[DATA_LENGTH];
|
||||||
|
* char timeBuf[80];
|
||||||
|
* time_t timestamp = 0;
|
||||||
|
* if (dataTypes & TELLSTICK_TEMPERATURE) {
|
||||||
|
* tdSensorValue(protocol, model, sensorId, TELLSTICK_TEMPERATURE, value, DATA_LENGTH, (int *)×tamp);
|
||||||
|
* strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", localtime(×tamp));
|
||||||
|
* printf("Temperature:\t%sº\t(%s)\n", value, timeBuf);
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
* \section sec_events Events
|
* \section sec_events Events
|
||||||
*
|
*
|
||||||
* To get events from either a TellStick Duo or if another software changes the
|
* To get events from either a TellStick Duo, another software changes the
|
||||||
* status of a device you have to register for a callback.
|
* status of a device, or new sensors values you have to register for a callback.
|
||||||
*
|
*
|
||||||
* \subsection sec_events_registering Registering for callbacks
|
* \subsection sec_events_registering Registering for callbacks
|
||||||
*
|
*
|
||||||
|
@ -198,6 +242,7 @@
|
||||||
* \li tdRegisterDeviceEvent()
|
* \li tdRegisterDeviceEvent()
|
||||||
* \li tdRegisterDeviceChangeEvent()
|
* \li tdRegisterDeviceChangeEvent()
|
||||||
* \li tdRegisterRawDeviceEvent()
|
* \li tdRegisterRawDeviceEvent()
|
||||||
|
* \li tdRegisterSensorEvent()
|
||||||
*
|
*
|
||||||
* These all work in the same way. The first parameter is a function-pointer to
|
* These all work in the same way. The first parameter is a function-pointer to
|
||||||
* the callback function. The second parameter is an optional void pointer. This
|
* the callback function. The second parameter is an optional void pointer. This
|
||||||
|
@ -212,13 +257,14 @@
|
||||||
*
|
*
|
||||||
* Many devices (for example motion detectors) resends their messages many times
|
* Many devices (for example motion detectors) resends their messages many times
|
||||||
* to ensure that they are received correctly. If a deviceeventcallback or
|
* to ensure that they are received correctly. If a deviceeventcallback or
|
||||||
* rawdeviceeventcallback in turn is calling a controlling function, for example tdTurnOn,
|
* rawdeviceeventcallback in turn is calling a controlling function, for example
|
||||||
* it may be neccessary to implement some solution to wait for the device to finish its
|
* tdTurnOn, it may be neccessary to implement some solution to wait for the
|
||||||
* resending, before executing the controlling function. See how this can be done in the python example.
|
* device to finish its resending, before executing the controlling function.
|
||||||
|
* See how this can be done in the python example.
|
||||||
*
|
*
|
||||||
* \subsection sec_events_callbacks Callbacks
|
* \subsection sec_events_callbacks Callbacks
|
||||||
*
|
*
|
||||||
* telldus-core currently implements three different callback function for
|
* telldus-core currently implements four different callback function for
|
||||||
* different purposes.
|
* different purposes.
|
||||||
*
|
*
|
||||||
* \subsubsection sec_events_callbacks_deviceevent DeviceEvent
|
* \subsubsection sec_events_callbacks_deviceevent DeviceEvent
|
||||||
|
@ -234,9 +280,10 @@
|
||||||
* - const char *data - For some methods this contains data. For TELLSTICK_DIM
|
* - const char *data - For some methods this contains data. For TELLSTICK_DIM
|
||||||
* this hold the current value.
|
* this hold the current value.
|
||||||
* - int callbackId - id of callback
|
* - int callbackId - id of callback
|
||||||
* - void *context - see "Registering for callbacks" for description
|
* - void *context - see \ref sec_events_registering for description
|
||||||
*
|
*
|
||||||
* \subsubsection sec_events_callbacks_devicechangeevent DeviceChangeEvent
|
* \subsubsection sec_events_callbacks_devicechangeevent DeviceChangeEvent
|
||||||
|
*
|
||||||
* This event is fired when the data around a device is changed. It can only be
|
* This event is fired when the data around a device is changed. It can only be
|
||||||
* triggered by another software. Use this callback to keep your list of devices
|
* triggered by another software. Use this callback to keep your list of devices
|
||||||
* in sync.
|
* in sync.
|
||||||
|
@ -256,19 +303,33 @@
|
||||||
* - TELLSTICK_CHANGE_PROTOCOL - Use tdGetProtocol() to read the new value.
|
* - TELLSTICK_CHANGE_PROTOCOL - Use tdGetProtocol() to read the new value.
|
||||||
* - TELLSTICK_CHANGE_MODEL - Use tdGetModel() to read the new value.
|
* - TELLSTICK_CHANGE_MODEL - Use tdGetModel() to read the new value.
|
||||||
* - int callbackId - id of callback
|
* - int callbackId - id of callback
|
||||||
* - void *context - see "Registering for callbacks" for description
|
* - void *context - see \ref sec_events_registering for description
|
||||||
*
|
*
|
||||||
* \subsubsection sec_events_callbacks_rawdeviceevent RawDeviceEvent
|
* \subsubsection sec_events_callbacks_rawdeviceevent RawDeviceEvent
|
||||||
*
|
*
|
||||||
* Use this callback with caution. It outputs everything from the Duo without
|
* Use this callback with caution. It outputs everything from a TellStick Duo
|
||||||
* any preprocessing. This can be used to get events from devices not already
|
* without any preprocessing. This can be used to get events from devices not
|
||||||
* configured.
|
* already configured.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* - const char *data - raw device data
|
* - const char *data - raw device data
|
||||||
* - int controllerId - id of receiving controller, can identify the TellStick if several exists in the system
|
* - int controllerId - id of receiving controller, can identify the TellStick if several exists in the system
|
||||||
* - int callbackId - id of callback
|
* - int callbackId - id of callback
|
||||||
* - void *context - see "Registering for callbacks" for description
|
* - void *context - see \ref sec_events_registering for description
|
||||||
|
*
|
||||||
|
* \subsubsection sec_events_callbacks_sensorevent SensorEvent
|
||||||
|
*
|
||||||
|
* This event is fired when a new sensor value is retrieved.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* - const char *protocol - The sensors protocol
|
||||||
|
* - const char *model - The model of the sensor
|
||||||
|
* - int id - The unique id for the sensor.
|
||||||
|
* - int dataType - Flags for which types of data the sensor supports
|
||||||
|
* - const char *value - A human readable string of the data
|
||||||
|
* - int timestamp - The timestamp when the latest value was received
|
||||||
|
* - int callbackId - id of callback
|
||||||
|
* - void *context - See \ref sec_events_registering for description
|
||||||
*
|
*
|
||||||
* \subsection sec_events_example Example
|
* \subsection sec_events_example Example
|
||||||
*
|
*
|
||||||
|
|
19
examples/php/live/authentication/common.php
Normal file
19
examples/php/live/authentication/common.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
require_once 'HTTP/OAuth/Consumer.php';
|
||||||
|
|
||||||
|
define('PUBLIC_KEY', '');
|
||||||
|
define('PRIVATE_KEY', '');
|
||||||
|
|
||||||
|
define('URL', 'http://api.telldus.net');
|
||||||
|
define('REQUEST_TOKEN', constant('URL').'/oauth/requestToken');
|
||||||
|
define('AUTHORIZE_TOKEN', constant('URL').'/oauth/authorize');
|
||||||
|
define('ACCESS_TOKEN', constant('URL').'/oauth/accessToken');
|
||||||
|
define('REQUEST_URI', constant('URL').'/xml');
|
||||||
|
|
||||||
|
define('BASE_URL', 'http://'.$_SERVER["SERVER_NAME"].dirname($_SERVER['REQUEST_URI']));
|
||||||
|
|
||||||
|
define('TELLSTICK_TURNON', 1);
|
||||||
|
define('TELLSTICK_TURNOFF', 2);
|
21
examples/php/live/authentication/getAccessToken.php
Normal file
21
examples/php/live/authentication/getAccessToken.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'common.php';
|
||||||
|
|
||||||
|
$consumer = new HTTP_OAuth_Consumer(constant('PUBLIC_KEY'), constant('PRIVATE_KEY'), $_SESSION['token'], $_SESSION['tokenSecret']);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$consumer->getAccessToken(constant('ACCESS_TOKEN'));
|
||||||
|
|
||||||
|
$_SESSION['accessToken'] = $consumer->getToken();
|
||||||
|
$_SESSION['accessTokenSecret'] = $consumer->getTokenSecret();
|
||||||
|
|
||||||
|
header('Location:index.php');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
?>
|
||||||
|
<p>Authorization failed!</p>
|
||||||
|
<p><a href="index.php">Go back</a></p>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
|
13
examples/php/live/authentication/getRequestToken.php
Normal file
13
examples/php/live/authentication/getRequestToken.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'common.php';
|
||||||
|
|
||||||
|
$consumer = new HTTP_OAuth_Consumer(constant('PUBLIC_KEY'), constant('PRIVATE_KEY'));
|
||||||
|
|
||||||
|
$consumer->getRequestToken(constant('REQUEST_TOKEN'), constant('BASE_URL').'/getAccessToken.php');
|
||||||
|
|
||||||
|
$_SESSION['token'] = $consumer->getToken();
|
||||||
|
$_SESSION['tokenSecret'] = $consumer->getTokenSecret();
|
||||||
|
|
||||||
|
$url = $consumer->getAuthorizeUrl(constant('AUTHORIZE_TOKEN'));
|
||||||
|
header('Location:'.$url);
|
47
examples/php/live/authentication/index.php
Normal file
47
examples/php/live/authentication/index.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'common.php';
|
||||||
|
|
||||||
|
if (isset($_GET['clear'])) {
|
||||||
|
session_destroy();
|
||||||
|
header('location:index.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($_SESSION['accessToken'])) {
|
||||||
|
?>We have no access token, <a href="getRequestToken.php">connect us</a><?php
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<p>We have access!</p>
|
||||||
|
<p>
|
||||||
|
In your system, store these values to do requests for this user:<br>
|
||||||
|
Token: <?php echo $_SESSION['accessToken']; ?><br>
|
||||||
|
Secret: <?php echo $_SESSION['accessTokenSecret']; ?>
|
||||||
|
</p>
|
||||||
|
<p><a href="index.php?clear">Clear the token and restart</a></p>
|
||||||
|
<p><a href="index.php?listDevices">List users devices</a></p>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
if (isset($_GET['listDevices'])) {
|
||||||
|
$consumer = new HTTP_OAuth_Consumer(constant('PUBLIC_KEY'), constant('PRIVATE_KEY'), $_SESSION['accessToken'], $_SESSION['accessTokenSecret']);
|
||||||
|
$params = array(
|
||||||
|
'supportedMethods' => constant('TELLSTICK_TURNON') | constant('TELLSTICK_TURNOFF'),
|
||||||
|
);
|
||||||
|
$response = $consumer->sendRequest(constant('REQUEST_URI').'/devices/list', $params, 'GET');
|
||||||
|
echo '<pre>';
|
||||||
|
echo( htmlentities($response->getBody()));
|
||||||
|
}
|
||||||
|
|
||||||
|
?><p><a href="index.php?listClients">List users clients</a></p><?php
|
||||||
|
|
||||||
|
if (isset($_GET['listClients'])) {
|
||||||
|
$consumer = new HTTP_OAuth_Consumer(constant('PUBLIC_KEY'), constant('PRIVATE_KEY'), $_SESSION['accessToken'], $_SESSION['accessTokenSecret']);
|
||||||
|
$params = array();
|
||||||
|
$response = $consumer->sendRequest(constant('REQUEST_URI').'/clients/list', $params, 'GET');
|
||||||
|
echo '<pre>';
|
||||||
|
echo( htmlentities($response->getBody()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
88
rfcmd/CMakeLists.txt
Normal file
88
rfcmd/CMakeLists.txt
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
cmake_minimum_required(VERSION 2.4)
|
||||||
|
|
||||||
|
INCLUDE_DIRECTORIES(
|
||||||
|
/usr/src/linux/include
|
||||||
|
)
|
||||||
|
|
||||||
|
#### Project: rfcmd ####
|
||||||
|
|
||||||
|
PROJECT(rfcmd)
|
||||||
|
|
||||||
|
SET(rfcmd_DESCRIPTION
|
||||||
|
"Sends RF remote commands through a Telldus TellStick"
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(rfcmd_SRCS
|
||||||
|
rfcmd.c
|
||||||
|
)
|
||||||
|
|
||||||
|
IF(${RFCMD_DEBUG})
|
||||||
|
ADD_DEFINITIONS( -DRFCMD_DEBUG )
|
||||||
|
ENDIF(${RFCMD_DEBUG})
|
||||||
|
|
||||||
|
IF (BUILD_RFCMD_WITH_LIBFTDI)
|
||||||
|
ADD_DEFINITIONS( -DLIBFTDI )
|
||||||
|
|
||||||
|
SET(rfcmd_SRCS
|
||||||
|
${rfcmd_SRCS}
|
||||||
|
ftdi.c
|
||||||
|
)
|
||||||
|
ENDIF (BUILD_RFCMD_WITH_LIBFTDI)
|
||||||
|
ADD_EXECUTABLE(rfcmd
|
||||||
|
${rfcmd_SRCS}
|
||||||
|
)
|
||||||
|
|
||||||
|
IF (BUILD_RFCMD_WITH_SEMAPHORES)
|
||||||
|
FIND_LIBRARY(SEM_LIBRARY rt)
|
||||||
|
TARGET_LINK_LIBRARIES(rfcmd
|
||||||
|
${SEM_LIBRARY}
|
||||||
|
)
|
||||||
|
ELSE (BUILD_RFCMD_WITH_SEMAPHORES)
|
||||||
|
ADD_DEFINITIONS( -DNO_SEMAPHORES )
|
||||||
|
ENDIF (BUILD_RFCMD_WITH_SEMAPHORES)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IF (BUILD_RFCMD_WITH_LIBFTDI)
|
||||||
|
FIND_LIBRARY(FTDI_LIBRARY ftdi)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(rfcmd
|
||||||
|
${FTDI_LIBRARY}
|
||||||
|
)
|
||||||
|
ENDIF (BUILD_RFCMD_WITH_LIBFTDI)
|
||||||
|
|
||||||
|
INSTALL(TARGETS rfcmd RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
|
IF (UNIX)
|
||||||
|
IF (GENERATE_MAN)
|
||||||
|
ADD_CUSTOM_COMMAND(
|
||||||
|
TARGET rfcmd
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND help2man -n ${rfcmd_DESCRIPTION} ./rfcmd > rfcmd.1
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMENT "Generating man file rfcmd.1"
|
||||||
|
)
|
||||||
|
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/rfcmd.1 DESTINATION share/man/man1)
|
||||||
|
ENDIF (GENERATE_MAN)
|
||||||
|
ENDIF (UNIX)
|
||||||
|
|
||||||
|
#### Project: find_telldus ####
|
||||||
|
|
||||||
|
IF (BUILD_RFCMD_WITH_LIBFTDI)
|
||||||
|
PROJECT(find_telldus)
|
||||||
|
|
||||||
|
SET(find_telldus_SRCS
|
||||||
|
find_telldus.c
|
||||||
|
)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(find_telldus
|
||||||
|
${find_telldus_SRCS}
|
||||||
|
)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(find_telldus
|
||||||
|
${FTDI_LIBRARY}
|
||||||
|
)
|
||||||
|
|
||||||
|
INSTALL(TARGETS find_telldus RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
|
ENDIF (BUILD_RFCMD_WITH_LIBFTDI)
|
340
rfcmd/COPYING
Normal file
340
rfcmd/COPYING
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) 19yy <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
22
rfcmd/Makefile
Normal file
22
rfcmd/Makefile
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
SRCS= rfcmd.c ftdi.c
|
||||||
|
CFLAGS=-O2 -Wall -I/usr/local/include
|
||||||
|
LFLAGS= -L/usr/local/lib -R/usr/local/lib
|
||||||
|
#linux:LFLAGS=-Wl,-rpath,/usr/local/lib
|
||||||
|
LIBS= -lftdi -lusb
|
||||||
|
PROG= rfcmd
|
||||||
|
FT= find_telldus
|
||||||
|
OBJS= $(SRCS:.c=.o)
|
||||||
|
CC= gcc
|
||||||
|
|
||||||
|
all: $(PROG) $(FT)
|
||||||
|
|
||||||
|
$(PROG): $(OBJS)
|
||||||
|
$(CC) $(CFLAGS) $(OBJS) -o $(PROG) $(LFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
rfcmd.o: rfcmd.c
|
||||||
|
|
||||||
|
ftdi.o: ftdi.c
|
||||||
|
|
||||||
|
$(FT): $(FT).c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $(FT).c $(LFLAGS) $(LIBS)
|
6
rfcmd/build.sh
Normal file
6
rfcmd/build.sh
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
make clean || { echo "Warning: make clean failed"; }
|
||||||
|
make || { echo "make failed"; exit 1; }
|
||||||
|
make install || { echo "make install failed"; exit 1; }
|
||||||
|
echo rfcmd built and installed!
|
42
rfcmd/find_telldus.c
Normal file
42
rfcmd/find_telldus.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* find_all.c
|
||||||
|
|
||||||
|
Example for ftdi_usb_find_all()
|
||||||
|
|
||||||
|
This program is distributed under the GPL, version 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ftdi.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ret, i;
|
||||||
|
struct ftdi_context ftdic;
|
||||||
|
struct ftdi_device_list *devlist, *curdev;
|
||||||
|
char manufacturer[128], description[128];
|
||||||
|
|
||||||
|
ftdi_init(&ftdic);
|
||||||
|
|
||||||
|
if((ret = ftdi_usb_find_all(&ftdic, &devlist, 0x1781, 0x0c30)) < 0) {
|
||||||
|
fprintf(stderr, "ftdi_usb_find_all failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Number of FTDI devices (telldus) found: %d\n", ret);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (curdev = devlist; curdev != NULL; i++) {
|
||||||
|
printf("Checking device: %d\n", i);
|
||||||
|
if((ret = ftdi_usb_get_strings(&ftdic, curdev->dev, manufacturer, 128, description, 128, NULL, 0)) < 0) {
|
||||||
|
fprintf(stderr, "ftdi_usb_get_strings failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
printf("Manufacturer: %s, Description: %s\n\n", manufacturer, description);
|
||||||
|
curdev = curdev->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdi_list_free(&devlist);
|
||||||
|
ftdi_deinit(&ftdic);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
110
rfcmd/ftdi.c
Normal file
110
rfcmd/ftdi.c
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* TellStick libftdi libusb version
|
||||||
|
* tested with 0.15 : http://www.intra2net.com/en/developer/libftdi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ftdi.h>
|
||||||
|
|
||||||
|
#define BAUD 4800
|
||||||
|
|
||||||
|
void ftdiCleanup(struct ftdi_context *ctx) {
|
||||||
|
ftdi_usb_close( ctx );
|
||||||
|
ftdi_deinit( ctx );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* use libftdi and libusb to send command
|
||||||
|
* no kernel driver needed
|
||||||
|
*/
|
||||||
|
int usbWriteFtdi(char *cmdstr)
|
||||||
|
{
|
||||||
|
struct ftdi_context ctx;
|
||||||
|
int device=0x0c30, vendor=0x1781;
|
||||||
|
int retrycnt;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (ftdi_init( &ctx )) {
|
||||||
|
char *err = ftdi_get_error_string(&ctx);
|
||||||
|
fprintf(stderr, "usb - init error: %s\n", err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = ftdi_usb_open(&ctx, vendor, device);
|
||||||
|
if (retval) {
|
||||||
|
char *err = ftdi_get_error_string(&ctx);
|
||||||
|
// FreeBSD says -3 when another rfcmd is running...
|
||||||
|
// Same on other systems?
|
||||||
|
if(retval == -3) {
|
||||||
|
fprintf(stderr, "usb - open error: %s. Is it busy?\n", err);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "usb - open error: %s\n", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdi_deinit( &ctx );
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftdi_usb_reset( &ctx )) {
|
||||||
|
char *err = ftdi_get_error_string(&ctx);
|
||||||
|
fprintf(stderr, "usb - reset error: %s\n", err);
|
||||||
|
retval = 3;
|
||||||
|
ftdiCleanup(&ctx);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftdi_disable_bitbang( &ctx ) || ftdi_set_baudrate(&ctx, BAUD)) {
|
||||||
|
char *err = ftdi_get_error_string(&ctx);
|
||||||
|
fprintf(stderr, "usb - init failed: %s\n", err);
|
||||||
|
ftdiCleanup(&ctx);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = ftdi_write_data( &ctx, cmdstr, strlen(cmdstr) );
|
||||||
|
if (retval < 0) {
|
||||||
|
char *err = ftdi_get_error_string(&ctx);
|
||||||
|
fprintf(stderr, "usb - write failed: %s\n", err);
|
||||||
|
ftdiCleanup(&ctx);
|
||||||
|
return 5;
|
||||||
|
} else if(retval != strlen(cmdstr)) {
|
||||||
|
fprintf(stderr, "usb - warning: %d bytes written instead of %d\n",
|
||||||
|
retval, (int)strlen(cmdstr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for Tellstick to be done with cmd, read back until we've received
|
||||||
|
* a \n indicating end of response.
|
||||||
|
* Wait max 5000 * 1000uS.
|
||||||
|
* XXX: Can the tellstick report errors?
|
||||||
|
*/
|
||||||
|
retval = 0;
|
||||||
|
retrycnt = 5000;
|
||||||
|
while (retrycnt--) {
|
||||||
|
unsigned char inb;
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
bytes = ftdi_read_data(&ctx, &inb, 1);
|
||||||
|
if (bytes == 0) {
|
||||||
|
usleep(1000);
|
||||||
|
} else if (bytes > 0) {
|
||||||
|
// Done when newline is received
|
||||||
|
if(inb == '\n') {
|
||||||
|
ftdiCleanup(&ctx);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char *err = ftdi_get_error_string(&ctx);
|
||||||
|
fprintf(stderr, "usb - read error: %s\n", err);
|
||||||
|
ftdiCleanup(&ctx);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we get here we failed to readback
|
||||||
|
fprintf(stderr, "usb - warning: never got newline response, giving up on wait\n");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
663
rfcmd/rfcmd.c
Normal file
663
rfcmd/rfcmd.c
Normal file
|
@ -0,0 +1,663 @@
|
||||||
|
/****************************************************************************
|
||||||
|
** rfcmd.c ***********************************************************
|
||||||
|
****************************************************************************
|
||||||
|
*
|
||||||
|
* rfcmd - utility to control NEXA and other RF remote receivers through a TellStick
|
||||||
|
* USB interface
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Tord Andersson <tord.o.andersson@gmail.com>
|
||||||
|
*
|
||||||
|
* License: GPL v. 2
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Tord Andersson <tord.o.andersson@gmail.com>
|
||||||
|
* Micke Prag <micke.prag@telldus.se>
|
||||||
|
* Gudmund Berggren
|
||||||
|
*
|
||||||
|
* Tapani Rintala / userspace libusb / libftdi - version 02-2009
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Modifications from rfcmd.c ver 0.2 done by Gudmund
|
||||||
|
* Added support for IKEA
|
||||||
|
* Note:
|
||||||
|
* 1. System code
|
||||||
|
* 2. Level 0 == Off (For dimmers and non dimmers)
|
||||||
|
* Level 1== 10%. (for dimmers)
|
||||||
|
* ....
|
||||||
|
* Level 9 == 90 % (for dimmers)
|
||||||
|
* Level 10 == 100 % (or ON for non dimmers)
|
||||||
|
* 3. Command line syntax:
|
||||||
|
* /usr/local/bin/rfcmd /dev/ttyUSB0 IKEA 0 1 10 1"
|
||||||
|
* Arg 1: device
|
||||||
|
* Arg 2: Protocoll
|
||||||
|
* Arg 3: System code
|
||||||
|
* Arg 4: Device code
|
||||||
|
* Arg 5: Level (0=off, 1 = 10%, 2=20%,...9=90%, 10=100%)
|
||||||
|
* Arg 6: DimStyle (0=instant change, 1=gradually change)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Modifications to rfcmd.c ver 2.1.0 done by Tord Andersson
|
||||||
|
* Introduced semaphore protection to avoid problems with simultaneous port
|
||||||
|
* access from several processes (typically cron jobs). Note! Need rt lib.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Modifications from rfcmd.c ver 2.1.0 done by Leo
|
||||||
|
* Added support for RISINGSUN
|
||||||
|
* Note:
|
||||||
|
* 1. Command line syntax:
|
||||||
|
* /usr/local/bin/rfcmd /dev/ttyUSB0 RISINGSUN 4 1 0"
|
||||||
|
* Arg 1: device
|
||||||
|
* Arg 2: protocol
|
||||||
|
* Arg 3: code
|
||||||
|
* Arg 4: device number
|
||||||
|
* Arg 5: Level (0=off, 1 = on)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Modifications from rfcmd.c ver 2.1.0 based on marvelous work by Snakehand
|
||||||
|
* See http://www.telldus.com/forum/viewtopic.php?t=97&start=63
|
||||||
|
* Added support for EVERFLOURISH
|
||||||
|
* Note:
|
||||||
|
* 1. Command line syntax:
|
||||||
|
* /usr/local/bin/rfcmd /dev/ttyUSB0 EVERFLOURISH 1 15
|
||||||
|
* Arg 1: device
|
||||||
|
* Arg 2: protocol
|
||||||
|
* Arg 3: device number (0..65535)
|
||||||
|
* Arg 4: Level (0=off, 15=on, 10=learn)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Modifications from rfcmd ver 2.1.1 done by Johan Ström
|
||||||
|
* Default disabled semaphores for FreeBSD.
|
||||||
|
* Added status readback in ftdi.c, instead of wasting time in sleep.
|
||||||
|
*
|
||||||
|
* FreeBSD does not have support in the GENERIC kernel semaphore.
|
||||||
|
* To enable usage of them, you'll have have the following option in your
|
||||||
|
* kernel configuration:
|
||||||
|
*
|
||||||
|
* options P1003_1B_SEMAPHORES
|
||||||
|
*
|
||||||
|
* However, on FreeBSD only libftdi seems to be working (at least on my system),
|
||||||
|
* since the device is not identified as a ucom device. And as we're accessing it
|
||||||
|
* via libftdi, libftdi makes sure simultaneous access is impossible.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
#ifndef NO_SEMAPHORES
|
||||||
|
#include <semaphore.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PROG_NAME "rfcmd"
|
||||||
|
#define PROG_VERSION "2.1.1"
|
||||||
|
/* #define RFCMD_DEBUG */
|
||||||
|
|
||||||
|
/* Local function declarations */
|
||||||
|
int createNexaString(const char * pHouseStr, const char * pChannelStr,
|
||||||
|
const char * pOn_offStr, char * pTxStr, int waveman);
|
||||||
|
int createSartanoString(const char * pChannelStr, const char * pOn_offStr,
|
||||||
|
char * pTxStr);
|
||||||
|
int createIkeaString(const char * pSystemStr, const char * pChannelStr,
|
||||||
|
const char * pLevelStr, const char *pDimStyle,
|
||||||
|
char * pStrReturn);
|
||||||
|
int createRisingSunString(const char * pCodeStr, const char* pUnitStr, const char * pOn_offStr,
|
||||||
|
char * pTxStr);
|
||||||
|
int createEverFlourishString(const char* pUnitStr, const char * pLevelStr,
|
||||||
|
char * pTxStr);
|
||||||
|
void printUsage(void);
|
||||||
|
void printVersion(void);
|
||||||
|
|
||||||
|
#ifdef LIBFTDI
|
||||||
|
int usbWriteFtdi(char *cmdstr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main( int argc, char **argv )
|
||||||
|
{
|
||||||
|
struct termios tio;
|
||||||
|
int fd = -1;
|
||||||
|
#ifndef NO_SEMAPHORES
|
||||||
|
sem_t * portMutex;
|
||||||
|
char SEM_NAME[]= "RFCMD_SEM"; /* Semaphore for multiple access ctrl */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
char txStr[100];
|
||||||
|
|
||||||
|
if( (argc == 6) && (strcmp(*(argv+2), "NEXA") == 0)) {
|
||||||
|
if (createNexaString(*(argv+3), *(argv+4), *(argv+5), txStr, 0) == 0) {
|
||||||
|
printUsage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* else - a send cmd string was created */
|
||||||
|
} else if( (argc == 6) && (strcmp(*(argv+2), "WAVEMAN") == 0)) {
|
||||||
|
if (createNexaString(*(argv+3),*(argv+4), *(argv+5), txStr, 1) == 0) {
|
||||||
|
printUsage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else if( (argc == 5) && (strcmp(*(argv+2), "SARTANO") == 0)) {
|
||||||
|
if (createSartanoString(*(argv+3), *(argv+4), txStr) == 0) {
|
||||||
|
printUsage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* else - a send cmd string was created */
|
||||||
|
} else if ( (argc == 7) && (strcmp(*(argv+2),"IKEA")==0) ) {
|
||||||
|
// System, Channel, Level, DimStyle, TXString
|
||||||
|
if ( createIkeaString(*(argv+3), *(argv+4), *(argv+5), *(argv+6),txStr) == 0 ) {
|
||||||
|
printUsage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* else - a send cmd string was created */
|
||||||
|
} else if ( (argc == 6) && (strcmp(*(argv+2),"RISINGSUN")==0) ) {
|
||||||
|
// Code, Unit, Power
|
||||||
|
if ( createRisingSunString(*(argv+3), *(argv+4), *(argv+5), txStr) == 0 ) {
|
||||||
|
printUsage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* else - a send cmd string was created */
|
||||||
|
} else if ( (argc == 5) && (strcmp(*(argv+2),"EVERFLOURISH")==0) ) {
|
||||||
|
// Unit, Level
|
||||||
|
if ( createEverFlourishString(*(argv+3), *(argv+4), txStr) == 0 ) {
|
||||||
|
printUsage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* else - a send cmd string was created */
|
||||||
|
} else if ( (argc >= 2) && (strcmp(*(argv+1),"--version")==0) ) {
|
||||||
|
printVersion();
|
||||||
|
exit(1);
|
||||||
|
} else { /* protocol or parameters not recognized */
|
||||||
|
printUsage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RFCMD_DEBUG
|
||||||
|
printf("txStr: %s\n", txStr);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(strlen(txStr) > 0) {
|
||||||
|
#ifndef NO_SEMAPHORES
|
||||||
|
/* create the semaphore - will reuse an existing one if it exists */
|
||||||
|
portMutex = sem_open(SEM_NAME,O_CREAT,0644,1);
|
||||||
|
if( portMutex == SEM_FAILED) {
|
||||||
|
fprintf(stderr, "%s - Error creating port semaphore\n", PROG_NAME);
|
||||||
|
perror("Semaphore open error");
|
||||||
|
sem_unlink(SEM_NAME);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lock semaphore to protect port from multiple access */
|
||||||
|
if(sem_wait(portMutex) != 0) {
|
||||||
|
fprintf(stderr, "%s - Error aquiring port semaphore\n", PROG_NAME);
|
||||||
|
sem_unlink(SEM_NAME);
|
||||||
|
sem_close(portMutex);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
if (strcmp(*(argv+1), "LIBUSB") != 0) {
|
||||||
|
if( 0 > ( fd = open( *(argv+1), O_RDWR ) ) ) {
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
fprintf(stderr, "%s - Error opening %s; You're on a FreeBSD system, you should probably use LIBUSB.\n", PROG_NAME, *(argv+1));
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "%s - Error opening %s\n", PROG_NAME, *(argv+1));
|
||||||
|
#endif
|
||||||
|
#ifndef NO_SEMAPHORES
|
||||||
|
if(sem_post(portMutex) != 0) {
|
||||||
|
fprintf(stderr, "%s - Error releasing port semaphore\n", PROG_NAME);
|
||||||
|
}
|
||||||
|
sem_unlink(SEM_NAME);
|
||||||
|
sem_close(portMutex);
|
||||||
|
#endif
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust serial port parameters */
|
||||||
|
bzero(&tio, sizeof(tio)); /* clear struct for new port settings */
|
||||||
|
tio.c_cflag = B4800 | CS8 | CLOCAL | CREAD; /* CREAD not used yet */
|
||||||
|
tio.c_iflag = IGNPAR;
|
||||||
|
tio.c_oflag = 0;
|
||||||
|
tio.c_ispeed = 4800;
|
||||||
|
tio.c_ospeed = 4800;
|
||||||
|
tcflush(fd, TCIFLUSH);
|
||||||
|
tcsetattr(fd,TCSANOW,&tio);
|
||||||
|
|
||||||
|
write(fd, txStr, strlen(txStr));
|
||||||
|
|
||||||
|
sleep(1); /* one second sleep to avoid device 'choking' */
|
||||||
|
close(fd); /* Modified : Close fd to make a clean exit */
|
||||||
|
} else {
|
||||||
|
#ifdef LIBFTDI
|
||||||
|
usbWriteFtdi( txStr );
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "%s - Support for libftdi is not compiled in, please recompile rfcmd with support for libftdi\n", PROG_NAME);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifndef NO_SEMAPHORES
|
||||||
|
/* Unlock semaphore */
|
||||||
|
if (sem_post(portMutex) != 0) {
|
||||||
|
fprintf(stderr, "%s - Error releasing port semaphore\n", PROG_NAME);
|
||||||
|
sem_unlink(SEM_NAME);
|
||||||
|
sem_close(portMutex);
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
sem_unlink(SEM_NAME);
|
||||||
|
sem_close(portMutex);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int createNexaString(const char * pHouseStr, const char * pChannelStr,
|
||||||
|
const char * pOn_offStr, char * pTxStr, int waveman)
|
||||||
|
{
|
||||||
|
* pTxStr = '\0'; /* Make sure tx string is empty */
|
||||||
|
int houseCode;
|
||||||
|
int channelCode;
|
||||||
|
int on_offCode;
|
||||||
|
int txCode = 0;
|
||||||
|
const int unknownCode = 0x6;
|
||||||
|
int bit;
|
||||||
|
int bitmask = 0x0001;
|
||||||
|
|
||||||
|
houseCode = (int)((* pHouseStr) - 65); /* House 'A'..'P' */
|
||||||
|
channelCode = atoi(pChannelStr) - 1; /* Channel 1..16 */
|
||||||
|
on_offCode = atoi(pOn_offStr); /* ON/OFF 0..1 */
|
||||||
|
|
||||||
|
#ifdef RFCMD_DEBUG
|
||||||
|
printf("House: %d, channel: %d, on_off: %d\n", houseCode, channelCode, on_offCode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* check converted parameters for validity */
|
||||||
|
if((houseCode < 0) || (houseCode > 15) || // House 'A'..'P'
|
||||||
|
(channelCode < 0) || (channelCode > 15) ||
|
||||||
|
(on_offCode < 0) || (on_offCode > 1))
|
||||||
|
{
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* b0..b11 txCode where 'X' will be represented by 1 for simplicity.
|
||||||
|
b0 will be sent first */
|
||||||
|
txCode = houseCode;
|
||||||
|
txCode |= (channelCode << 4);
|
||||||
|
if (waveman && on_offCode == 0) {
|
||||||
|
} else {
|
||||||
|
txCode |= (unknownCode << 8);
|
||||||
|
txCode |= (on_offCode << 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert to send cmd string */
|
||||||
|
strcat(pTxStr,"S");
|
||||||
|
for(bit=0;bit<12;bit++)
|
||||||
|
{
|
||||||
|
if((bitmask & txCode) == 0) {
|
||||||
|
/* bit timing might need further refinement */
|
||||||
|
strcat(pTxStr," ` `"); /* 320 us high, 960 us low, 320 us high, 960 us low */
|
||||||
|
/* strcat(pTxStr,"$k$k"); *//* 360 us high, 1070 us low, 360 us high, 1070 us low */
|
||||||
|
} else { /* add 'X' (floating bit) */
|
||||||
|
strcat(pTxStr," `` "); /* 320 us high, 960 us low, 960 us high, 320 us low */
|
||||||
|
/*strcat(pTxStr,"$kk$"); *//* 360 us high, 1070 us low, 1070 us high, 360 us low */
|
||||||
|
}
|
||||||
|
bitmask = bitmask<<1;
|
||||||
|
}
|
||||||
|
/* add stop/sync bit and command termination char '+'*/
|
||||||
|
strcat(pTxStr," }+");
|
||||||
|
/* strcat(pTxStr,"$}+"); */
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RFCMD_DEBUG
|
||||||
|
printf("txCode: %04X\n", txCode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return strlen(pTxStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int createSartanoString(const char * pChannelStr, const char * pOn_offStr,
|
||||||
|
char * pTxStr)
|
||||||
|
{
|
||||||
|
* pTxStr = '\0'; /* Make sure tx string is empty */
|
||||||
|
int on_offCode;
|
||||||
|
int bit;
|
||||||
|
|
||||||
|
on_offCode = atoi(pOn_offStr); /* ON/OFF 0..1 */
|
||||||
|
|
||||||
|
#ifdef RFCMD_DEBUG
|
||||||
|
printf("Channel: %s, on_off: %d\n", pChannelStr, on_offCode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* check converted parameters for validity */
|
||||||
|
if((strlen(pChannelStr) != 10) ||
|
||||||
|
(on_offCode < 0) || (on_offCode > 1)) {
|
||||||
|
} else {
|
||||||
|
strcat(pTxStr,"S");
|
||||||
|
for(bit=0;bit<=9;bit++)
|
||||||
|
{
|
||||||
|
if(strncmp(pChannelStr+bit, "1", 1) == 0) { //If it is a "1"
|
||||||
|
strcat(pTxStr,"$k$k");
|
||||||
|
} else {
|
||||||
|
strcat(pTxStr,"$kk$");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (on_offCode >= 1)
|
||||||
|
strcat(pTxStr,"$k$k$kk$"); //the "turn on"-code
|
||||||
|
else
|
||||||
|
strcat(pTxStr,"$kk$$k$k"); //the "turn off"-code
|
||||||
|
|
||||||
|
/* add stop/sync bit and command termination char '+'*/
|
||||||
|
strcat(pTxStr,"$k+");
|
||||||
|
}
|
||||||
|
|
||||||
|
return strlen(pTxStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int createIkeaString( const char * pSystemStr, const char * pChannelStr, const char * pLevelStr, const char *pDimStyle, char * pStrReturn)
|
||||||
|
{
|
||||||
|
*pStrReturn = '\0'; /* Make sure tx string is empty */
|
||||||
|
|
||||||
|
const char STARTCODE[] = "STTTTTTª";
|
||||||
|
const char TT[] = "TT";
|
||||||
|
const char A[] = "ª";
|
||||||
|
int systemCode = atoi(pSystemStr) - 1; /* System 1..16 */
|
||||||
|
int channelCode = atoi(pChannelStr); /* Channel 1..10 */
|
||||||
|
int Level = atoi(pLevelStr); /* off,10,20,..,90,on */
|
||||||
|
int DimStyle = atoi(pDimStyle);
|
||||||
|
int intCode = 0;
|
||||||
|
int checksum1 = 0;
|
||||||
|
int checksum2 = 0;
|
||||||
|
int intFade ;
|
||||||
|
int i ;
|
||||||
|
int rawChannelCode = 0;
|
||||||
|
|
||||||
|
/* check converted parameters for validity */
|
||||||
|
if ( (channelCode <= 0) || (channelCode > 10) ||
|
||||||
|
(systemCode < 0) || (systemCode > 15) ||
|
||||||
|
(Level < 0) || (Level > 10) ||
|
||||||
|
(DimStyle < 0) || (DimStyle > 1))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelCode == 10) {
|
||||||
|
channelCode = 0;
|
||||||
|
}
|
||||||
|
rawChannelCode = (1<<(9-channelCode));
|
||||||
|
|
||||||
|
strcat(pStrReturn, STARTCODE ) ; //Startcode, always like this;
|
||||||
|
intCode = (systemCode << 10) | rawChannelCode;
|
||||||
|
|
||||||
|
for ( i = 13; i >= 0; --i) {
|
||||||
|
if ((intCode>>i) & 1) {
|
||||||
|
strcat(pStrReturn, TT );
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
checksum2++;
|
||||||
|
} else {
|
||||||
|
checksum1++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strcat(pStrReturn,A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checksum1 %2 == 0) {
|
||||||
|
strcat(pStrReturn, TT );
|
||||||
|
} else {
|
||||||
|
strcat(pStrReturn, A) ; //1st checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checksum2 %2 == 0) {
|
||||||
|
strcat(pStrReturn, TT );
|
||||||
|
} else {
|
||||||
|
strcat(pStrReturn, A ) ; //2nd checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DimStyle == 1) {
|
||||||
|
intFade = 11 << 4; //Smooth
|
||||||
|
} else {
|
||||||
|
intFade = 1 << 4; //Instant
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( Level )
|
||||||
|
{
|
||||||
|
case 0 :
|
||||||
|
intCode = (10 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 1 :
|
||||||
|
intCode = (1 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 2 :
|
||||||
|
intCode = (2 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 3 :
|
||||||
|
intCode = (3 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 4 :
|
||||||
|
intCode = (4 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 5 :
|
||||||
|
intCode = (5 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 6 :
|
||||||
|
intCode = (6 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 7 :
|
||||||
|
intCode = (7 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 8 :
|
||||||
|
intCode = (8 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 9 :
|
||||||
|
intCode = (9 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
case 10 :
|
||||||
|
default :
|
||||||
|
intCode = (0 | intFade) ; //Concat level and fade
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum1 = 0;
|
||||||
|
checksum2 = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 6; ++i) {
|
||||||
|
if ((intCode>>i) & 1) {
|
||||||
|
strcat(pStrReturn, TT);
|
||||||
|
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
checksum1++;
|
||||||
|
} else {
|
||||||
|
checksum2++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strcat(pStrReturn, A );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checksum1 %2 == 0) {
|
||||||
|
strcat(pStrReturn, TT);
|
||||||
|
} else {
|
||||||
|
strcat(pStrReturn, A ) ; //2nd checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checksum2 %2 == 0) {
|
||||||
|
strcat(pStrReturn, TT );
|
||||||
|
} else {
|
||||||
|
strcat(pStrReturn, A ) ; //2nd checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(pStrReturn, "+");
|
||||||
|
|
||||||
|
return strlen(pStrReturn);
|
||||||
|
}
|
||||||
|
|
||||||
|
int createRisingSunString(const char * pCodeStr, const char * pUnitStr, const char * pOn_offStr,
|
||||||
|
char * pTxStr)
|
||||||
|
{
|
||||||
|
* pTxStr = '\0'; /* Make sure tx string is empty */
|
||||||
|
int on_offCode;
|
||||||
|
int unit;
|
||||||
|
int code;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
on_offCode = atoi(pOn_offStr); /* ON/OFF 0..1 */
|
||||||
|
code = atoi (pCodeStr);
|
||||||
|
unit = atoi (pUnitStr);
|
||||||
|
|
||||||
|
#ifdef RFCMD_DEBUG
|
||||||
|
printf("Code: %s, unit: %s, on_off: %d\n", pCodeStr, pUnitStr, on_offCode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* check converted parameters for validity */
|
||||||
|
if((code < 1) || (code > 4) ||
|
||||||
|
(unit < 1) || (unit > 4) ||
|
||||||
|
(on_offCode < 0) || (on_offCode > 1)) {
|
||||||
|
} else {
|
||||||
|
strcat(pTxStr,"S.e");
|
||||||
|
for (i = 1; i <= 4; ++i) {
|
||||||
|
if (i == code) {
|
||||||
|
strcat (pTxStr, ".e.e");
|
||||||
|
} else {
|
||||||
|
strcat (pTxStr, "e..e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 1; i <= 4; ++i) {
|
||||||
|
if (i == unit) {
|
||||||
|
strcat (pTxStr, ".e.e");
|
||||||
|
} else {
|
||||||
|
strcat (pTxStr, "e..e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (on_offCode >= 1) {
|
||||||
|
strcat(pTxStr,"e..ee..ee..ee..e+"); //the "turn on"-code
|
||||||
|
} else {
|
||||||
|
strcat(pTxStr,"e..ee..ee..e.e.e+"); //the "turn off"-code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strlen(pTxStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int everflourish_find_code(unsigned int x) {
|
||||||
|
unsigned int bits[16] = { 0xf ,0xa ,0x7 ,0xe,
|
||||||
|
0xf ,0xd ,0x9 ,0x1,
|
||||||
|
0x1 ,0x2 ,0x4 ,0x8,
|
||||||
|
0x3 ,0x6 ,0xc ,0xb };
|
||||||
|
unsigned int bit = 1;
|
||||||
|
unsigned int res = 0x5;
|
||||||
|
int i;
|
||||||
|
unsigned int lo,hi;
|
||||||
|
|
||||||
|
if ((x&0x3)==3) {
|
||||||
|
lo = x & 0x00ff;
|
||||||
|
hi = x & 0xff00;
|
||||||
|
lo += 4;
|
||||||
|
if (lo>0x100) lo = 0x12;
|
||||||
|
x = lo | hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0;i<16;i++) {
|
||||||
|
if (x&bit) {
|
||||||
|
res = res ^ bits[i];
|
||||||
|
}
|
||||||
|
bit = bit << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int createEverFlourishString(const char * pUnitStr, const char * pLevelStr,
|
||||||
|
char * pTxStr)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
int level;
|
||||||
|
int unit;
|
||||||
|
unsigned int check;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
unit = atoi(pUnitStr);
|
||||||
|
level = atoi(pLevelStr); /* ON=15, OFF=0, LEARN=10 */
|
||||||
|
check = everflourish_find_code(unit);
|
||||||
|
|
||||||
|
#ifdef RFCMD_DEBUG
|
||||||
|
printf("unit: %d, level: %d\n", unit, level);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* check converted parameters for validity */
|
||||||
|
if((unit < 0) || (unit > 0xffff) ||
|
||||||
|
(level < 0) || (level > 15)) {
|
||||||
|
} else {
|
||||||
|
const char ssss = 85;
|
||||||
|
const char sssl = 84; // 0
|
||||||
|
const char slss = 69; // 1
|
||||||
|
|
||||||
|
const char bits[2] = {sssl,slss};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
char preamble[] = {'R', 5, 'T', 114,60,1,1,105,ssss,ssss};
|
||||||
|
memcpy(pTxStr, preamble, sizeof(preamble));
|
||||||
|
len += sizeof(preamble);
|
||||||
|
|
||||||
|
for(i=15;i>=0;i--) pTxStr[len++]=bits[(unit>>i)&0x01];
|
||||||
|
for(i=3;i>=0;i--) pTxStr[len++]=bits[(check>>i)&0x01];
|
||||||
|
for(i=3;i>=0;i--) pTxStr[len++]=bits[(level>>i)&0x01];
|
||||||
|
|
||||||
|
pTxStr[len++] = ssss;
|
||||||
|
pTxStr[len++] = '+';
|
||||||
|
}
|
||||||
|
|
||||||
|
pTxStr[len] = '\0';
|
||||||
|
return strlen(pTxStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printUsage(void)
|
||||||
|
{
|
||||||
|
printf("Usage: rfcmd DEVICE PROTOCOL [PROTOCOL_ARGUMENTS] \n");
|
||||||
|
printf("\n");
|
||||||
|
#ifdef LIBFTDI
|
||||||
|
printf("\t DEVICE: /dev/ttyUSB[0..n] | LIBUSB\n" );
|
||||||
|
#else
|
||||||
|
printf("\t DEVICE: /dev/ttyUSB[0..n]\n" );
|
||||||
|
#endif
|
||||||
|
printf("\t PROTOCOLS: NEXA, SARTANO, WAVEMAN, IKEA, RISINGSUN, EVERFLOURISH\n" );
|
||||||
|
printf("\n");
|
||||||
|
printf("\t PROTOCOL ARGUMENTS - NEXA, WAVEMAN:\n");
|
||||||
|
printf("\t\tHOUSE_CODE: A..P\n\t\tCHANNEL: 1..16\n\t\tOFF_ON: 0..1\n" );
|
||||||
|
printf("\n");
|
||||||
|
printf("\t PROTOCOL ARGUMENTS - SARTANO:\n");
|
||||||
|
printf("\t\tCHANNEL: 0000000000..1111111111\n\t\tOFF_ON: 0..1\n" );
|
||||||
|
printf("\n");
|
||||||
|
printf("\t PROTOCOL ARGUMENTS - IKEA:\n");
|
||||||
|
printf("\t\tSYSTEM: 1..16\n\t\tDEVICE: 1..10\n");
|
||||||
|
printf("\t\tDIM_LEVEL: 0..10\n\t\tDIM_STYLE: 0..1\n" );
|
||||||
|
printf("\n");
|
||||||
|
printf("\t PROTOCOL ARGUMENTS - RISINGSUN:\n");
|
||||||
|
printf("\t\tCODE: 1..4\n\t\tDEVICE: 1..4\n");
|
||||||
|
printf("\t\tOFF_ON: 0..1\n" );
|
||||||
|
printf("\n");
|
||||||
|
printf("\t PROTOCOL ARGUMENTS - EVERFLOURISH:\n");
|
||||||
|
printf("\t\tDEVICE: 0..65535\n");
|
||||||
|
printf("\t\tLEVEL: 0=off, 10=learn, 15=on\n" );
|
||||||
|
printf("\n");
|
||||||
|
printf("Report bugs to <info.tech@telldus.se>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void printVersion(void) {
|
||||||
|
printf("%s v%s\n", PROG_NAME, PROG_VERSION);
|
||||||
|
printf("\n");
|
||||||
|
printf("Copyright (C) Tord Andersson 2007\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Written by:\n");
|
||||||
|
printf("Tord Andersson, Micke Prag, Gudmund Berggren, Tapani Rintala\n");
|
||||||
|
printf("and Johan Ström\n");
|
||||||
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!DOCTYPE TS><TS version="1.1" language="sv_SE">
|
|
||||||
<context>
|
|
||||||
<name>Icon</name>
|
|
||||||
<message>
|
|
||||||
<location filename="icon.cpp" line="25"/>
|
|
||||||
<source>TellStick</source>
|
|
||||||
<translation>TellStick</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="icon.cpp" line="117"/>
|
|
||||||
<source>&On</source>
|
|
||||||
<translation>&På</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="icon.cpp" line="122"/>
|
|
||||||
<source>O&ff</source>
|
|
||||||
<translation>&Av</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="icon.cpp" line="100"/>
|
|
||||||
<source>&Configure devices</source>
|
|
||||||
<translation>&Konfigurera enheter</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="icon.cpp" line="105"/>
|
|
||||||
<source>&Quit</source>
|
|
||||||
<translation>&Avsluta</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="icon.cpp" line="67"/>
|
|
||||||
<source>Error</source>
|
|
||||||
<translation>Fel</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="icon.cpp" line="67"/>
|
|
||||||
<source>An error occurred while trying to transmit</source>
|
|
||||||
<translation>Ett fel uppstod vid försök att sända</translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
</TS>
|
|
|
@ -1,216 +0,0 @@
|
||||||
//
|
|
||||||
// C++ Implementation: icon
|
|
||||||
//
|
|
||||||
// Description:
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Author: Micke Prag <micke.prag@telldus.se>, (C) 2007
|
|
||||||
//
|
|
||||||
// Copyright: See COPYING file that comes with this distribution
|
|
||||||
//
|
|
||||||
//
|
|
||||||
#include "icon.h"
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QMenu>
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QFile>
|
|
||||||
#include "telldus-core.h"
|
|
||||||
|
|
||||||
Icon::Icon()
|
|
||||||
: QObject()
|
|
||||||
{
|
|
||||||
this->setMenu();
|
|
||||||
connect( &i, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(activated(QSystemTrayIcon::ActivationReason)));
|
|
||||||
i.setIcon( QIcon(":/images/lamp-on.png") );
|
|
||||||
i.setToolTip( tr("TellStick") );
|
|
||||||
i.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Icon::~Icon()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fn Icon::activated( QSystemTrayIcon::ActivationReason reason )
|
|
||||||
*/
|
|
||||||
void Icon::activated( QSystemTrayIcon::ActivationReason reason )
|
|
||||||
{
|
|
||||||
if (reason == QSystemTrayIcon::DoubleClick) {
|
|
||||||
if (hasTelldusSetup()) {
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fn Icon::bell()
|
|
||||||
*/
|
|
||||||
void Icon::bell()
|
|
||||||
{
|
|
||||||
QAction *action = (QAction *) sender();
|
|
||||||
int retval = tdBell( action->data().toInt() );
|
|
||||||
if (retval != TELLSTICK_SUCCESS) {
|
|
||||||
char *errorString = tdGetErrorString( retval );
|
|
||||||
i.showMessage( tr("Error"), tr("An error occurred while trying to transmit!\n\n%1").arg(errorString), QSystemTrayIcon::Critical );
|
|
||||||
free( errorString );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fn Icon::dim()
|
|
||||||
*/
|
|
||||||
void Icon::dim()
|
|
||||||
{
|
|
||||||
QAction *action = (QAction *) sender();
|
|
||||||
int intId = action->data().toString().section(":", 0, 0).toInt();
|
|
||||||
int intLevel = action->data().toString().section(":", 1, 1).toInt();
|
|
||||||
//i.showMessage( "", QString::number(intId));
|
|
||||||
int retval = tdDim( intId, intLevel );
|
|
||||||
if (retval != TELLSTICK_SUCCESS) {
|
|
||||||
char *errorString = tdGetErrorString( retval );
|
|
||||||
i.showMessage( tr("Error"), tr("An error occurred while trying to transmit!\n\n%1").arg(errorString), QSystemTrayIcon::Critical );
|
|
||||||
free( errorString );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fn Icon::on()
|
|
||||||
*/
|
|
||||||
void Icon::on()
|
|
||||||
{
|
|
||||||
QAction *action = (QAction *) sender();
|
|
||||||
int retval = tdTurnOn( action->data().toInt() );
|
|
||||||
if (retval != TELLSTICK_SUCCESS) {
|
|
||||||
char *errorString = tdGetErrorString( retval );
|
|
||||||
i.showMessage( tr("Error"), tr("An error occurred while trying to transmit!\n\n%1").arg(errorString), QSystemTrayIcon::Critical );
|
|
||||||
free( errorString );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fn Icon::off()
|
|
||||||
*/
|
|
||||||
void Icon::off()
|
|
||||||
{
|
|
||||||
QAction *action = (QAction *) sender();
|
|
||||||
int retval = tdTurnOff( action->data().toInt() );
|
|
||||||
if (retval != TELLSTICK_SUCCESS) {
|
|
||||||
char *errorString = tdGetErrorString( retval );
|
|
||||||
i.showMessage( tr("Error"), tr("An error occurred while trying to transmit!\n\n%1").arg(errorString), QSystemTrayIcon::Critical );
|
|
||||||
free( errorString );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fn Icon::configure()
|
|
||||||
*/
|
|
||||||
void Icon::configure()
|
|
||||||
{
|
|
||||||
QProcess *process = new QProcess(this);
|
|
||||||
connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(setMenu()));
|
|
||||||
process->setWorkingDirectory(QCoreApplication::applicationDirPath());
|
|
||||||
process->start("TelldusSetup.exe");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fn Icon::setMenu()
|
|
||||||
*/
|
|
||||||
void Icon::setMenu()
|
|
||||||
{
|
|
||||||
menu.clear();
|
|
||||||
|
|
||||||
int intNum = tdGetNumberOfDevices();
|
|
||||||
int index = 0;
|
|
||||||
while (index < intNum) {
|
|
||||||
addDevice(index, &menu);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
menu.addSeparator();
|
|
||||||
|
|
||||||
if (hasTelldusSetup()) {
|
|
||||||
QAction *configure = menu.addAction(tr("&Configure devices"));
|
|
||||||
connect(configure, SIGNAL(triggered()), this, SLOT(configure()));
|
|
||||||
configure->setIcon( QIcon(":/images/preferences-system.png") );
|
|
||||||
}
|
|
||||||
|
|
||||||
QAction *quit = menu.addAction(tr("&Quit"));
|
|
||||||
quit->setIcon( QIcon(":/images/system-log-out.png") );
|
|
||||||
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
|
|
||||||
|
|
||||||
i.setContextMenu(&menu);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Icon::addDevice( int index, QMenu *menu ) {
|
|
||||||
int intId = tdGetDeviceId(index);
|
|
||||||
QMenu *m = menu->addMenu( tdGetName(intId) );
|
|
||||||
|
|
||||||
int methods = tdMethods(intId);
|
|
||||||
if (methods & TELLSTICK_TURNON) {
|
|
||||||
QAction *on = m->addAction(tr("&On"));
|
|
||||||
on->setIcon(QIcon(":/images/lamp-on.png"));
|
|
||||||
on->setData( intId );
|
|
||||||
connect( on, SIGNAL(triggered()), this, SLOT(on()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methods & TELLSTICK_DIM) {
|
|
||||||
QAction *dim = m->addAction(tr("90%"));
|
|
||||||
dim->setData( QString("%1:230").arg(intId) );
|
|
||||||
connect( dim, SIGNAL(triggered()), this, SLOT(dim()));
|
|
||||||
|
|
||||||
dim = m->addAction(tr("80%"));
|
|
||||||
dim->setData( QString("%1:204").arg(intId) );
|
|
||||||
connect( dim, SIGNAL(triggered()), this, SLOT(dim()));
|
|
||||||
|
|
||||||
dim = m->addAction(tr("70%"));
|
|
||||||
dim->setData( QString("%1:179").arg(intId) );
|
|
||||||
connect( dim, SIGNAL(triggered()), this, SLOT(dim()));
|
|
||||||
|
|
||||||
dim = m->addAction(tr("60%"));
|
|
||||||
dim->setData( QString("%1:153").arg(intId) );
|
|
||||||
connect( dim, SIGNAL(triggered()), this, SLOT(dim()));
|
|
||||||
|
|
||||||
dim = m->addAction(tr("50%"));
|
|
||||||
dim->setData( QString("%1:128").arg(intId) );
|
|
||||||
connect( dim, SIGNAL(triggered()), this, SLOT(dim()));
|
|
||||||
|
|
||||||
dim = m->addAction(tr("40%"));
|
|
||||||
dim->setData( QString("%1:102").arg(intId) );
|
|
||||||
connect( dim, SIGNAL(triggered()), this, SLOT(dim()));
|
|
||||||
|
|
||||||
dim = m->addAction(tr("30%"));
|
|
||||||
dim->setData( QString("%1:77").arg(intId) );
|
|
||||||
connect( dim, SIGNAL(triggered()), this, SLOT(dim()));
|
|
||||||
|
|
||||||
dim = m->addAction(tr("20%"));
|
|
||||||
dim->setData( QString("%1:51").arg(intId) );
|
|
||||||
connect( dim, SIGNAL(triggered()), this, SLOT(dim()));
|
|
||||||
|
|
||||||
dim = m->addAction(tr("10%"));
|
|
||||||
dim->setData( QString("%1:25").arg(intId) );
|
|
||||||
connect( dim, SIGNAL(triggered()), this, SLOT(dim()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methods & TELLSTICK_TURNON) {
|
|
||||||
QAction *off = m->addAction(tr("O&ff"));
|
|
||||||
off->setData( intId );
|
|
||||||
off->setIcon(QIcon(":/images/lamp-off.png"));
|
|
||||||
connect( off, SIGNAL(triggered()), this, SLOT(off()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methods & TELLSTICK_BELL) {
|
|
||||||
QAction *bell = m->addAction(tr("&Bell"));
|
|
||||||
bell->setData( intId );
|
|
||||||
bell->setIcon(QIcon(":/images/bell.png"));
|
|
||||||
connect( bell, SIGNAL(triggered()), this, SLOT(bell()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Icon::hasTelldusSetup() {
|
|
||||||
return QFile::exists("TelldusSetup.exe");
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
//
|
|
||||||
// C++ Interface: icon
|
|
||||||
//
|
|
||||||
// Description:
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Author: Micke Prag <micke.prag@telldus.se>, (C) 2007
|
|
||||||
//
|
|
||||||
// Copyright: See COPYING file that comes with this distribution
|
|
||||||
//
|
|
||||||
//
|
|
||||||
#ifndef ICON_H
|
|
||||||
#define ICON_H
|
|
||||||
|
|
||||||
#include <QSystemTrayIcon>
|
|
||||||
#include <QMenu>
|
|
||||||
|
|
||||||
/**
|
|
||||||
@author Micke Prag <micke.prag@telldus.se>
|
|
||||||
*/
|
|
||||||
class Icon : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
Icon();
|
|
||||||
|
|
||||||
~Icon();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QSystemTrayIcon i;
|
|
||||||
QMenu menu;
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void activated( QSystemTrayIcon::ActivationReason reason );
|
|
||||||
void setMenu();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void bell();
|
|
||||||
void dim();
|
|
||||||
void on();
|
|
||||||
void off();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void configure();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void addDevice( int index, QMenu *menu );
|
|
||||||
static bool hasTelldusSetup();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
|
@ -1,47 +0,0 @@
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2006 by Micke Prag *
|
|
||||||
* micke.prag@telldus.se *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License as published by *
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QTranslator>
|
|
||||||
#include <QLocale>
|
|
||||||
#include "icon.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
QApplication a( argc, argv );
|
|
||||||
|
|
||||||
QCoreApplication::setOrganizationName("Telldus");
|
|
||||||
QCoreApplication::setOrganizationDomain("telldus.se");
|
|
||||||
QCoreApplication::setApplicationName("SysTray");
|
|
||||||
|
|
||||||
Q_INIT_RESOURCE(resource);
|
|
||||||
|
|
||||||
QTranslator qtTranslator;
|
|
||||||
qtTranslator.load("qt_" + QLocale::system().name());
|
|
||||||
a.installTranslator(&qtTranslator);
|
|
||||||
|
|
||||||
QTranslator myappTranslator;
|
|
||||||
myappTranslator.load("SysTray_" + QLocale::system().name());
|
|
||||||
a.installTranslator(&myappTranslator);
|
|
||||||
|
|
||||||
Icon icon;
|
|
||||||
return a.exec();
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
<RCC>
|
|
||||||
<qresource prefix="/" >
|
|
||||||
<file>images/bell.png</file>
|
|
||||||
<file>images/lamp-on.png</file>
|
|
||||||
<file>images/lamp-off.png</file>
|
|
||||||
<file>images/preferences-system.png</file>
|
|
||||||
<file>images/system-log-out.png</file>
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
|
@ -1,23 +0,0 @@
|
||||||
TEMPLATE = app
|
|
||||||
|
|
||||||
SOURCES += main.cpp \
|
|
||||||
icon.cpp
|
|
||||||
|
|
||||||
!macx:LIBS += -ltelldus-core -L../bin
|
|
||||||
macx{
|
|
||||||
LIBS += -framework telldus-core
|
|
||||||
ICON = images/systray.icns
|
|
||||||
}
|
|
||||||
win32{
|
|
||||||
TARGET = ../../bin/SysTray
|
|
||||||
CONFIG += release
|
|
||||||
}
|
|
||||||
unix{
|
|
||||||
TARGET = ../bin/systray
|
|
||||||
CONFIG += debug
|
|
||||||
}
|
|
||||||
HEADERS += icon.h
|
|
||||||
#menu.h
|
|
||||||
RESOURCES += resource.qrc
|
|
||||||
RC_FILE = systray.rc
|
|
||||||
TRANSLATIONS = SysTray_sv.ts
|
|
|
@ -1 +0,0 @@
|
||||||
IDI_ICON1 ICON DISCARDABLE "images/systray.ico"
|
|
|
@ -1,4 +0,0 @@
|
||||||
TEMPLATE = subdirs
|
|
||||||
SUBDIRS = src
|
|
||||||
CONFIG += warn_on
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CallbackDispatcher.h"
|
#include "CallbackDispatcher.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
using namespace TelldusCore;
|
using namespace TelldusCore;
|
||||||
|
|
||||||
|
@ -28,7 +29,9 @@ bool TDDeviceEventDispatcher::done() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TDDeviceEventDispatcher::run() {
|
void TDDeviceEventDispatcher::run() {
|
||||||
|
char *str = wrapStdString(strData);
|
||||||
d->event(deviceId, method, strData.c_str(), d->id, d->context);
|
d->event(deviceId, method, strData.c_str(), d->id, d->context);
|
||||||
|
|
||||||
doneRunning = true;
|
doneRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,9 @@ bool Client::getBoolFromService(const Message &msg) {
|
||||||
|
|
||||||
int Client::getIntegerFromService(const Message &msg) {
|
int Client::getIntegerFromService(const Message &msg) {
|
||||||
std::wstring response = sendToService(msg);
|
std::wstring response = sendToService(msg);
|
||||||
|
if (response.compare(L"") == 0) {
|
||||||
|
return TELLSTICK_ERROR_COMMUNICATING_SERVICE;
|
||||||
|
}
|
||||||
return Message::takeInt(&response);
|
return Message::takeInt(&response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +184,8 @@ void Client::run(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring clientMessage = d->eventSocket.read(5000); //testing 5 second timeout
|
std::wstring clientMessage = d->eventSocket.read(1000); //testing 5 second timeout
|
||||||
|
|
||||||
while(clientMessage != L""){
|
while(clientMessage != L""){
|
||||||
//a message arrived
|
//a message arrived
|
||||||
std::wstring type = Message::takeString(&clientMessage);
|
std::wstring type = Message::takeString(&clientMessage);
|
||||||
|
@ -282,16 +286,46 @@ void Client::cleanupCallbacks() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring Client::sendToService(const Message &msg) {
|
std::wstring Client::sendToService(const Message &msg) {
|
||||||
Socket s;
|
|
||||||
s.connect(L"TelldusClient");
|
int tries = 0;
|
||||||
if (!s.isConnected()) { //Connection failed
|
std::wstring readData;
|
||||||
TelldusCore::Message msg;
|
while(tries < 20){
|
||||||
msg.addArgument(TELLSTICK_ERROR_CONNECTING_SERVICE);
|
tries++;
|
||||||
return msg;
|
if(tries == 20){
|
||||||
|
TelldusCore::Message msg;
|
||||||
|
msg.addArgument(TELLSTICK_ERROR_CONNECTING_SERVICE);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
Socket s;
|
||||||
|
s.connect(L"TelldusClient");
|
||||||
|
if (!s.isConnected()) { //Connection failed
|
||||||
|
printf("Connection failed\n\r");
|
||||||
|
msleep(500);
|
||||||
|
continue; //retry
|
||||||
|
}
|
||||||
|
s.write(msg.data());
|
||||||
|
if (!s.isConnected()) { //Connection failed sometime during operation... (better check here, instead of 5 seconds timeout later)
|
||||||
|
printf("Connection failed after write\n\r");
|
||||||
|
msleep(500);
|
||||||
|
continue; //retry
|
||||||
|
}
|
||||||
|
readData = s.read(8000); //TODO changed to 10000 from 5000, how much does this do...?
|
||||||
|
if(readData == L""){
|
||||||
|
printf("Readdata nothing\n\r");
|
||||||
|
msleep(500);
|
||||||
|
continue; //TODO can we be really sure it SHOULD be anything?
|
||||||
|
//TODO perhaps break here instead?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s.isConnected()) { //Connection failed sometime during operation...
|
||||||
|
printf("Connection failed in the end\n\r");
|
||||||
|
msleep(500);
|
||||||
|
continue; //retry
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
s.write(msg.data());
|
|
||||||
|
|
||||||
return s.read(5000);
|
return readData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::stopThread(){
|
void Client::stopThread(){
|
||||||
|
|
|
@ -57,6 +57,9 @@ using namespace TelldusCore;
|
||||||
* @def TELLSTICK_SUCCESS
|
* @def TELLSTICK_SUCCESS
|
||||||
* Error code. Returned when the command succeeded.
|
* Error code. Returned when the command succeeded.
|
||||||
*
|
*
|
||||||
|
* @def TELLSTICK_ERROR_BROKEN_PIPE
|
||||||
|
* Error code. Pipe broken during communication.
|
||||||
|
*
|
||||||
* @def TELLSTICK_ERROR_NOT_FOUND
|
* @def TELLSTICK_ERROR_NOT_FOUND
|
||||||
* Error code. Returned if a TellStick was not found on the system.
|
* Error code. Returned if a TellStick was not found on the system.
|
||||||
*
|
*
|
||||||
|
@ -82,6 +85,13 @@ using namespace TelldusCore;
|
||||||
* Error code. The client library received a response from the service
|
* Error code. The client library received a response from the service
|
||||||
* it did not understand.
|
* it did not understand.
|
||||||
*
|
*
|
||||||
|
* @def TELLSTICK_ERROR_SYNTAX
|
||||||
|
* Error code. Input/command could not be parsed or didn't follow
|
||||||
|
* input rules.
|
||||||
|
*
|
||||||
|
* @def TELLSTICK_ERROR_COMMUNICATING_SERVICE
|
||||||
|
* Error code. Timeout waiting for response from the Telldus Service.
|
||||||
|
*
|
||||||
* @def TELLSTICK_ERROR_UNKNOWN
|
* @def TELLSTICK_ERROR_UNKNOWN
|
||||||
* Error code. An unkown error has occurred.
|
* Error code. An unkown error has occurred.
|
||||||
*/
|
*/
|
||||||
|
@ -479,10 +489,16 @@ int WINAPI tdMethods(int id, int methodsSupported){
|
||||||
* @sa TELLSTICK_ERROR_PERMISSION_DENIED
|
* @sa TELLSTICK_ERROR_PERMISSION_DENIED
|
||||||
* @sa TELLSTICK_ERROR_DEVICE_NOT_FOUND
|
* @sa TELLSTICK_ERROR_DEVICE_NOT_FOUND
|
||||||
* @sa TELLSTICK_ERROR_METHOD_NOT_SUPPORTED
|
* @sa TELLSTICK_ERROR_METHOD_NOT_SUPPORTED
|
||||||
|
* @sa TELLSTICK_ERROR_COMMUNICATION
|
||||||
|
* @sa TELLSTICK_ERROR_CONNECTING_SERVICE
|
||||||
|
* @sa TELLSTICK_ERROR_UNKNOWN_RESPONSE
|
||||||
|
* @sa TELLSTICK_ERROR_SYNTAX
|
||||||
|
* @sa TELLSTICK_ERROR_BROKEN_PIPE
|
||||||
|
* @sa TELLSTICK_ERROR_COMMUNICATING_SERVICE
|
||||||
* @sa TELLSTICK_ERROR_UNKNOWN
|
* @sa TELLSTICK_ERROR_UNKNOWN
|
||||||
*/
|
*/
|
||||||
char * WINAPI tdGetErrorString(int intErrorNo) {
|
char * WINAPI tdGetErrorString(int intErrorNo) {
|
||||||
const int numResponses = 8;
|
const int numResponses = 10;
|
||||||
const char *responses[numResponses] = {
|
const char *responses[numResponses] = {
|
||||||
"Success",
|
"Success",
|
||||||
"TellStick not found",
|
"TellStick not found",
|
||||||
|
@ -491,7 +507,10 @@ char * WINAPI tdGetErrorString(int intErrorNo) {
|
||||||
"The method you tried to use is not supported by the device",
|
"The method you tried to use is not supported by the device",
|
||||||
"An error occurred while communicating with TellStick",
|
"An error occurred while communicating with TellStick",
|
||||||
"Could not connect to the Telldus Service",
|
"Could not connect to the Telldus Service",
|
||||||
"Received an unknown response"
|
"Received an unknown response",
|
||||||
|
"Syntax error",
|
||||||
|
"Broken pipe"
|
||||||
|
"An error occured while communicating with the Telldus Service"
|
||||||
};
|
};
|
||||||
std::string strReturn;
|
std::string strReturn;
|
||||||
intErrorNo = abs(intErrorNo); //We don't use negative values here.
|
intErrorNo = abs(intErrorNo); //We don't use negative values here.
|
||||||
|
@ -511,8 +530,12 @@ char * WINAPI tdGetErrorString(int intErrorNo) {
|
||||||
* @returns TELLSTICK_SUCCESS on success or one of the errorcodes on failure
|
* @returns TELLSTICK_SUCCESS on success or one of the errorcodes on failure
|
||||||
*/
|
*/
|
||||||
int WINAPI tdSendRawCommand(const char *command, int reserved) {
|
int WINAPI tdSendRawCommand(const char *command, int reserved) {
|
||||||
|
std::wstring wcommand;
|
||||||
|
for(int i = 0; i < strlen(command);++i) {
|
||||||
|
wcommand.append(1, (unsigned char)command[i]);
|
||||||
|
}
|
||||||
Message msg(L"tdSendRawCommand");
|
Message msg(L"tdSendRawCommand");
|
||||||
msg.addArgument(command);
|
msg.addArgument(wcommand);
|
||||||
msg.addArgument(reserved);
|
msg.addArgument(reserved);
|
||||||
return Client::getIntegerFromService(msg);
|
return Client::getIntegerFromService(msg);
|
||||||
}
|
}
|
||||||
|
@ -534,11 +557,36 @@ void WINAPI tdDisconnectTellStickController(int vid, int pid, const char *serial
|
||||||
Client::getWStringFromService(msg);
|
Client::getWStringFromService(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to iterate over all sensors. Iterate until
|
||||||
|
* TELLSTICK_SUCCESS is not returned
|
||||||
|
* @param protocol A byref string where the protocol of the sensor will be placed
|
||||||
|
* @param protocolLen The length of the \c protocol parameter
|
||||||
|
* @param model A byref string where the model of the sensor will be placed
|
||||||
|
* @param modelLen The length of the \c model parameter
|
||||||
|
* @param id A byref int where the id of the sensor will be placed
|
||||||
|
* @param dataTypes A byref int with flags for the supported sensor values
|
||||||
|
* @returns TELLSTICK_SUCCESS if there is more sensors to be fetched
|
||||||
|
*/
|
||||||
int WINAPI tdSensor(char *protocol, int protocolLen, char *model, int modelLen, int *id, int *dataTypes) {
|
int WINAPI tdSensor(char *protocol, int protocolLen, char *model, int modelLen, int *id, int *dataTypes) {
|
||||||
Client *client = Client::getInstance();
|
Client *client = Client::getInstance();
|
||||||
return client->getSensor(protocol, protocolLen, model, modelLen, id, dataTypes);
|
return client->getSensor(protocol, protocolLen, model, modelLen, id, dataTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get one of the supported sensor values from a sensor. Make sure it support
|
||||||
|
* the value type first by calling tdSensor(). The triplet \c protocol,
|
||||||
|
* \c model, and \c id together identifies a sensor.
|
||||||
|
* @param protocol The protocol for the sensor
|
||||||
|
* @param model The model for the sensor
|
||||||
|
* @param id The id of the sensor
|
||||||
|
* @param dataType One of the datatype to retrieve
|
||||||
|
* @param value A byref string where the value will be places
|
||||||
|
* @param len The length of the \c value parameter
|
||||||
|
* @param timestamp A byref int where the timestamp of the value will be placed
|
||||||
|
* @returns TELLSTICK_SUCCESS if the value could be fetched or one of the
|
||||||
|
* errorcodes on failure
|
||||||
|
*/
|
||||||
int WINAPI tdSensorValue(const char *protocol, const char *model, int id, int dataType, char *value, int len, int *timestamp) {
|
int WINAPI tdSensorValue(const char *protocol, const char *model, int id, int dataType, char *value, int len, int *timestamp) {
|
||||||
Message msg(L"tdSensorValue");
|
Message msg(L"tdSensorValue");
|
||||||
msg.addArgument(protocol);
|
msg.addArgument(protocol);
|
||||||
|
@ -562,4 +610,4 @@ int WINAPI tdSensorValue(const char *protocol, const char *model, int id, int da
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*\@}*/
|
/* @} */
|
||||||
|
|
|
@ -115,6 +115,9 @@ extern "C" {
|
||||||
#define TELLSTICK_ERROR_COMMUNICATION -5
|
#define TELLSTICK_ERROR_COMMUNICATION -5
|
||||||
#define TELLSTICK_ERROR_CONNECTING_SERVICE -6
|
#define TELLSTICK_ERROR_CONNECTING_SERVICE -6
|
||||||
#define TELLSTICK_ERROR_UNKNOWN_RESPONSE -7
|
#define TELLSTICK_ERROR_UNKNOWN_RESPONSE -7
|
||||||
|
#define TELLSTICK_ERROR_SYNTAX -8
|
||||||
|
#define TELLSTICK_ERROR_BROKEN_PIPE -9
|
||||||
|
#define TELLSTICK_ERROR_COMMUNICATING_SERVICE -10
|
||||||
#define TELLSTICK_ERROR_UNKNOWN -99
|
#define TELLSTICK_ERROR_UNKNOWN -99
|
||||||
|
|
||||||
//Device typedef
|
//Device typedef
|
||||||
|
|
|
@ -23,21 +23,70 @@ Message::~Message(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Message::addArgument(const std::wstring &value) {
|
void Message::addArgument(const std::wstring &value) {
|
||||||
std::wstringstream st;
|
//std::wstringstream st;
|
||||||
st << (int)value.size();
|
//st << (int)value.size();
|
||||||
this->append(st.str());
|
this->append(TelldusCore::intToWstring(value.size())); //st.str());
|
||||||
this->append(L":");
|
this->append(L":");
|
||||||
this->append(value);
|
this->append(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Message::addArgument(int value) {
|
void Message::addArgument(int value) {
|
||||||
std::wstringstream st;
|
//std::wstringstream st;
|
||||||
st << (int)value;
|
//st << (int)value;
|
||||||
this->append(L"i");
|
this->append(L"i");
|
||||||
this->append(st.str());
|
this->append(TelldusCore::intToWstring(value)); // st.str());
|
||||||
this->append(L"s");
|
this->append(L"s");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void Message::addSpecialArgument(const std::wstring &value){
|
||||||
|
int i = 0;
|
||||||
|
while(i<1000000){
|
||||||
|
i++;
|
||||||
|
|
||||||
|
char numstr[21]; // enough to hold all numbers up to 64-bits
|
||||||
|
//sprintf(numstr, "%d", value.size());
|
||||||
|
//this->append(TelldusCore::charToWstring(numstr)); //.str());
|
||||||
|
|
||||||
|
itoa(value.size(), numstr, 10);
|
||||||
|
std::string test(numstr);
|
||||||
|
std::wstring temp(test.length(), L' ');
|
||||||
|
std::copy(test.begin(), test.end(), temp.begin());
|
||||||
|
|
||||||
|
this->append(temp);
|
||||||
|
this->append(L":");
|
||||||
|
this->append(value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
std::wstringstream st;
|
||||||
|
st << (int)value.size();
|
||||||
|
this->append(st.str());
|
||||||
|
this->append(L":");
|
||||||
|
this->append(value);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Message::addSpecialArgument(int value){
|
||||||
|
int i = 0;
|
||||||
|
while(i<1000000){
|
||||||
|
i++;
|
||||||
|
/*
|
||||||
|
//std::wstringstream st;
|
||||||
|
//st << (int)value;
|
||||||
|
this->append(L"i");
|
||||||
|
//this->append(st.str());
|
||||||
|
this->append(L"s");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
void Message::addSpecialArgument(const char *value){
|
||||||
|
this->addSpecialArgument(TelldusCore::charToWstring(value));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void Message::addArgument(const char *value) {
|
void Message::addArgument(const char *value) {
|
||||||
this->addArgument(TelldusCore::charToWstring(value));
|
this->addArgument(TelldusCore::charToWstring(value));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ namespace TelldusCore {
|
||||||
~Message(void);
|
~Message(void);
|
||||||
|
|
||||||
void addArgument(const std::wstring &);
|
void addArgument(const std::wstring &);
|
||||||
|
//void addSpecialArgument(const std::wstring &);
|
||||||
|
//void addSpecialArgument(int);
|
||||||
|
//void addSpecialArgument(const char *);
|
||||||
void addArgument(int);
|
void addArgument(int);
|
||||||
void addArgument(const char *);
|
void addArgument(const char *);
|
||||||
|
|
||||||
|
|
|
@ -78,9 +78,9 @@ std::wstring Socket::read() {
|
||||||
std::wstring Socket::read(int timeout) {
|
std::wstring Socket::read(int timeout) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
char inbuf[BUFSIZE];
|
char inbuf[BUFSIZE];
|
||||||
memset(inbuf, '\0', sizeof(inbuf));
|
|
||||||
|
|
||||||
FD_SET(d->socket, &d->infds);
|
FD_SET(d->socket, &d->infds);
|
||||||
|
std::string msg;
|
||||||
while(isConnected()) {
|
while(isConnected()) {
|
||||||
tv.tv_sec = floor(timeout / 1000.0);
|
tv.tv_sec = floor(timeout / 1000.0);
|
||||||
tv.tv_usec = timeout % 1000;
|
tv.tv_usec = timeout % 1000;
|
||||||
|
@ -93,21 +93,28 @@ std::wstring Socket::read(int timeout) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int received = recv(d->socket, inbuf, BUFSIZE - 1, 0);
|
int received = BUFSIZE;
|
||||||
if (received <= 0) {
|
while(received >= (BUFSIZE - 1)){
|
||||||
|
memset(inbuf, '\0', sizeof(inbuf));
|
||||||
|
received = recv(d->socket, inbuf, BUFSIZE - 1, 0);
|
||||||
|
if(received > 0){
|
||||||
|
msg.append(std::string(inbuf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (received < 0) {
|
||||||
TelldusCore::MutexLocker locker(&d->mutex);
|
TelldusCore::MutexLocker locker(&d->mutex);
|
||||||
d->connected = false;
|
d->connected = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string msg(inbuf);
|
|
||||||
return TelldusCore::charToWstring(msg.c_str());
|
return TelldusCore::charToWstring(msg.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Socket::stopReadWait(){
|
void Socket::stopReadWait(){
|
||||||
TelldusCore::MutexLocker locker(&d->mutex);
|
TelldusCore::MutexLocker locker(&d->mutex);
|
||||||
d->connected = false;
|
d->connected = false;
|
||||||
|
//TODO somehow signal the socket here?
|
||||||
}
|
}
|
||||||
|
|
||||||
void Socket::write(const std::wstring &msg) {
|
void Socket::write(const std::wstring &msg) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ Socket::~Socket(void){
|
||||||
SetEvent(d->readEvent); //signal for break
|
SetEvent(d->readEvent); //signal for break
|
||||||
if (d->hPipe != INVALID_HANDLE_VALUE) {
|
if (d->hPipe != INVALID_HANDLE_VALUE) {
|
||||||
CloseHandle(d->hPipe);
|
CloseHandle(d->hPipe);
|
||||||
|
d->hPipe = 0;
|
||||||
}
|
}
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
@ -89,39 +90,52 @@ std::wstring Socket::read(int timeout){
|
||||||
|
|
||||||
memset(&oOverlap, 0, sizeof(OVERLAPPED));
|
memset(&oOverlap, 0, sizeof(OVERLAPPED));
|
||||||
|
|
||||||
d->readEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
d->readEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
oOverlap.hEvent = d->readEvent;
|
oOverlap.hEvent = d->readEvent;
|
||||||
BOOL fSuccess = false;
|
BOOL fSuccess = false;
|
||||||
|
std::wstring returnString;
|
||||||
|
bool moreData = true;
|
||||||
|
|
||||||
memset(&buf, 0, BUFSIZE);
|
while(moreData){
|
||||||
|
moreData = false;
|
||||||
|
memset(&buf, 0, sizeof(buf));
|
||||||
|
|
||||||
ReadFile( d->hPipe, &buf, sizeof(wchar_t)*BUFSIZE, &cbBytesRead, &oOverlap);
|
ReadFile( d->hPipe, &buf, sizeof(buf)-sizeof(wchar_t), &cbBytesRead, &oOverlap);
|
||||||
|
|
||||||
result = WaitForSingleObject(oOverlap.hEvent, timeout);
|
result = WaitForSingleObject(oOverlap.hEvent, timeout);
|
||||||
|
|
||||||
if(!d->running){
|
if(!d->running){
|
||||||
CancelIo(d->hPipe);
|
CancelIo(d->hPipe);
|
||||||
CloseHandle(d->readEvent);
|
WaitForSingleObject(oOverlap.hEvent, INFINITE);
|
||||||
return L"";
|
d->readEvent = 0;
|
||||||
}
|
CloseHandle(oOverlap.hEvent);
|
||||||
|
return L"";
|
||||||
if (result == WAIT_TIMEOUT) {
|
|
||||||
CancelIo(d->hPipe);
|
|
||||||
CloseHandle(d->readEvent);
|
|
||||||
return L"";
|
|
||||||
}
|
|
||||||
fSuccess = GetOverlappedResult(d->hPipe, &oOverlap, &cbBytesRead, false);
|
|
||||||
if (!fSuccess) {
|
|
||||||
DWORD err = GetLastError();
|
|
||||||
if (err == ERROR_BROKEN_PIPE) {
|
|
||||||
d->connected = false;
|
|
||||||
}
|
}
|
||||||
buf[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CancelIo(d->hPipe);
|
if (result == WAIT_TIMEOUT) {
|
||||||
CloseHandle(d->readEvent);
|
CancelIo(d->hPipe);
|
||||||
return buf;
|
// Cancel, we still need to cleanup
|
||||||
|
}
|
||||||
|
fSuccess = GetOverlappedResult(d->hPipe, &oOverlap, &cbBytesRead, true);
|
||||||
|
|
||||||
|
if (!fSuccess) {
|
||||||
|
DWORD err = GetLastError();
|
||||||
|
|
||||||
|
if(err == ERROR_MORE_DATA){
|
||||||
|
moreData = true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
buf[0] = 0;
|
||||||
|
}
|
||||||
|
if (err == ERROR_BROKEN_PIPE) {
|
||||||
|
d->connected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
returnString.append(buf);
|
||||||
|
}
|
||||||
|
d->readEvent = 0;
|
||||||
|
CloseHandle(oOverlap.hEvent);
|
||||||
|
return returnString;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Socket::write(const std::wstring &msg){
|
void Socket::write(const std::wstring &msg){
|
||||||
|
@ -129,26 +143,33 @@ void Socket::write(const std::wstring &msg){
|
||||||
OVERLAPPED oOverlap;
|
OVERLAPPED oOverlap;
|
||||||
DWORD bytesWritten = 0;
|
DWORD bytesWritten = 0;
|
||||||
int result;
|
int result;
|
||||||
BOOL fSuccess;
|
BOOL fSuccess = false;
|
||||||
|
|
||||||
memset(&oOverlap, 0, sizeof(OVERLAPPED));
|
memset(&oOverlap, 0, sizeof(OVERLAPPED));
|
||||||
|
|
||||||
HANDLE writeEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
HANDLE writeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
oOverlap.hEvent = writeEvent;
|
oOverlap.hEvent = writeEvent;
|
||||||
|
|
||||||
WriteFile(d->hPipe, msg.data(), (DWORD)msg.length()*sizeof(wchar_t), &bytesWritten, &oOverlap);
|
BOOL writeSuccess = WriteFile(d->hPipe, msg.data(), (DWORD)msg.length()*sizeof(wchar_t), &bytesWritten, &oOverlap);
|
||||||
|
result = GetLastError();
|
||||||
result = WaitForSingleObject(writeEvent, 500);
|
if (writeSuccess || result == ERROR_IO_PENDING) {
|
||||||
if (result == WAIT_TIMEOUT) {
|
result = WaitForSingleObject(writeEvent, 500);
|
||||||
CancelIo(d->hPipe);
|
if (result == WAIT_TIMEOUT) {
|
||||||
CloseHandle(writeEvent);
|
CancelIo(d->hPipe);
|
||||||
d->connected = false;
|
WaitForSingleObject(oOverlap.hEvent, INFINITE);
|
||||||
return;
|
CloseHandle(writeEvent);
|
||||||
|
CloseHandle(d->hPipe);
|
||||||
|
d->hPipe = 0;
|
||||||
|
d->connected = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fSuccess = GetOverlappedResult(d->hPipe, &oOverlap, &bytesWritten, TRUE);
|
||||||
}
|
}
|
||||||
fSuccess = GetOverlappedResult(d->hPipe, &oOverlap, &bytesWritten, TRUE);
|
|
||||||
CloseHandle(writeEvent);
|
CloseHandle(writeEvent);
|
||||||
if (!fSuccess) {
|
if (!fSuccess) {
|
||||||
CancelIo(d->hPipe);
|
CloseHandle(d->hPipe);
|
||||||
|
d->hPipe = 0;
|
||||||
d->connected = false;
|
d->connected = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -91,17 +92,58 @@ bool TelldusCore::comparei(std::wstring stringA, std::wstring stringB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring TelldusCore::intToWstring(int value) {
|
std::wstring TelldusCore::intToWstring(int value) {
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
//no stream used
|
||||||
|
//TODO! Make effective and safe...
|
||||||
|
wchar_t numstr[21]; // enough to hold all numbers up to 64-bits
|
||||||
|
_itow_s(value, numstr, sizeof(numstr), 10);
|
||||||
|
std::wstring newstring(numstr);
|
||||||
|
return newstring;
|
||||||
|
//return TelldusCore::charToWstring(stdstring.c_str());
|
||||||
|
//std::wstring temp = TelldusCore::charToWstring(stdstring.c_str());
|
||||||
|
//std::wstring temp(stdstring.length(), L' ');
|
||||||
|
//std::copy(stdstring.begin(), stdstring.end(), temp.begin());
|
||||||
|
//return temp;
|
||||||
|
#else
|
||||||
std::wstringstream st;
|
std::wstringstream st;
|
||||||
st << value;
|
st << value;
|
||||||
return st.str();
|
return st.str();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TelldusCore::intToString(int value) {
|
std::string TelldusCore::intToString(int value) {
|
||||||
|
//Not sure if this is neecssary (for ordinary stringstream that is)
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
char numstr[21]; // enough to hold all numbers up to 64-bits
|
||||||
|
_itoa_s(value, numstr, sizeof(numstr), 10);
|
||||||
|
std::string stdstring(numstr);
|
||||||
|
return stdstring;
|
||||||
|
#else
|
||||||
std::stringstream st;
|
std::stringstream st;
|
||||||
st << value;
|
st << value;
|
||||||
return st.str();
|
return st.str();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
std::wstring TelldusCore::intToWStringSafe(int value){
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
//no stream used
|
||||||
|
//TODO! Make effective and safe...
|
||||||
|
char numstr[21]; // enough to hold all numbers up to 64-bits
|
||||||
|
itoa(value, numstr, 10);
|
||||||
|
std::string stdstring(numstr);
|
||||||
|
return TelldusCore::charToWstring(stdstring.c_str());
|
||||||
|
//std::wstring temp = TelldusCore::charToWstring(stdstring.c_str());
|
||||||
|
//std::wstring temp(stdstring.length(), L' ');
|
||||||
|
//std::copy(stdstring.begin(), stdstring.end(), temp.begin());
|
||||||
|
//return temp;
|
||||||
|
#else
|
||||||
|
return TelldusCore::intToWString(value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
int TelldusCore::wideToInteger(const std::wstring &input){
|
int TelldusCore::wideToInteger(const std::wstring &input){
|
||||||
std::wstringstream inputstream;
|
std::wstringstream inputstream;
|
||||||
inputstream << input;
|
inputstream << input;
|
||||||
|
@ -158,3 +200,48 @@ std::string TelldusCore::wideToString(const std::wstring &input) {
|
||||||
return retval;
|
return retval;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string TelldusCore::formatf(const char *format, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
std::string retval = sformatf(format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TelldusCore::sformatf(const char *format, va_list ap) {
|
||||||
|
//This code is based on code from the Linux man-pages project (man vsprintf)
|
||||||
|
int n;
|
||||||
|
int size = 100; /* Guess we need no more than 100 bytes. */
|
||||||
|
char *p, *np;
|
||||||
|
|
||||||
|
if ((p = (char*)malloc(size)) == NULL) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/* Try to print in the allocated space. */
|
||||||
|
n = vsnprintf(p, size, format, ap);
|
||||||
|
|
||||||
|
/* If that worked, return the string. */
|
||||||
|
if (n > -1 && n < size) {
|
||||||
|
std::string retval(p);
|
||||||
|
free(p);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Else try again with more space. */
|
||||||
|
|
||||||
|
if (n > -1) { /* glibc 2.1 */
|
||||||
|
size = n+1; /* precisely what is needed */
|
||||||
|
} else { /* glibc 2.0 */
|
||||||
|
size *= 2; /* twice the old size */
|
||||||
|
}
|
||||||
|
if ((np = (char *)realloc (p, size)) == NULL) {
|
||||||
|
free(p);
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
p = np;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define STRING_H
|
#define STRING_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
namespace TelldusCore {
|
namespace TelldusCore {
|
||||||
std::wstring charToWstring(const char *value);
|
std::wstring charToWstring(const char *value);
|
||||||
|
@ -10,10 +11,14 @@ namespace TelldusCore {
|
||||||
|
|
||||||
bool comparei(std::wstring stringA, std::wstring stringB);
|
bool comparei(std::wstring stringA, std::wstring stringB);
|
||||||
std::wstring intToWstring(int value);
|
std::wstring intToWstring(int value);
|
||||||
|
//std::wstring intToWStringSafe(int value);
|
||||||
std::string intToString(int value);
|
std::string intToString(int value);
|
||||||
std::string wideToString(const std::wstring &input);
|
std::string wideToString(const std::wstring &input);
|
||||||
|
|
||||||
int wideToInteger(const std::wstring &input);
|
int wideToInteger(const std::wstring &input);
|
||||||
|
|
||||||
|
std::string formatf(const char *format, ...);
|
||||||
|
std::string sformatf(const char *format, va_list ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //STRING_H
|
#endif //STRING_H
|
||||||
|
|
|
@ -19,10 +19,12 @@ SET( telldus-service_SRCS
|
||||||
Device.cpp
|
Device.cpp
|
||||||
DeviceManager.cpp
|
DeviceManager.cpp
|
||||||
Event.cpp
|
Event.cpp
|
||||||
|
Log.cpp
|
||||||
Sensor.cpp
|
Sensor.cpp
|
||||||
Settings.cpp
|
Settings.cpp
|
||||||
TelldusMain.cpp
|
TelldusMain.cpp
|
||||||
TellStick.cpp
|
TellStick.cpp
|
||||||
|
Timer.cpp
|
||||||
EventUpdateManager.cpp
|
EventUpdateManager.cpp
|
||||||
)
|
)
|
||||||
SET( telldus-service_protocol_SRCS
|
SET( telldus-service_protocol_SRCS
|
||||||
|
@ -34,6 +36,8 @@ SET( telldus-service_protocol_SRCS
|
||||||
ProtocolComen.cpp
|
ProtocolComen.cpp
|
||||||
ProtocolEverflourish.h
|
ProtocolEverflourish.h
|
||||||
ProtocolEverflourish.cpp
|
ProtocolEverflourish.cpp
|
||||||
|
ProtocolFineoffset.h
|
||||||
|
ProtocolFineoffset.cpp
|
||||||
ProtocolFuhaote.h
|
ProtocolFuhaote.h
|
||||||
ProtocolFuhaote.cpp
|
ProtocolFuhaote.cpp
|
||||||
ProtocolGroup.h
|
ProtocolGroup.h
|
||||||
|
@ -42,8 +46,12 @@ SET( telldus-service_protocol_SRCS
|
||||||
ProtocolHasta.cpp
|
ProtocolHasta.cpp
|
||||||
ProtocolIkea.h
|
ProtocolIkea.h
|
||||||
ProtocolIkea.cpp
|
ProtocolIkea.cpp
|
||||||
|
ProtocolMandolyn.h
|
||||||
|
ProtocolMandolyn.cpp
|
||||||
ProtocolNexa.h
|
ProtocolNexa.h
|
||||||
ProtocolNexa.cpp
|
ProtocolNexa.cpp
|
||||||
|
ProtocolOregon.h
|
||||||
|
ProtocolOregon.cpp
|
||||||
ProtocolRisingSun.h
|
ProtocolRisingSun.h
|
||||||
ProtocolRisingSun.cpp
|
ProtocolRisingSun.cpp
|
||||||
ProtocolSartano.h
|
ProtocolSartano.h
|
||||||
|
@ -72,11 +80,13 @@ SET( telldus-service_HDRS
|
||||||
DeviceManager.h
|
DeviceManager.h
|
||||||
Event.h
|
Event.h
|
||||||
EventHandler.h
|
EventHandler.h
|
||||||
|
EventUpdateManager.h
|
||||||
|
Log.h
|
||||||
Sensor.h
|
Sensor.h
|
||||||
Settings.h
|
Settings.h
|
||||||
TelldusMain.h
|
TelldusMain.h
|
||||||
TellStick.h
|
TellStick.h
|
||||||
EventUpdateManager.h
|
Timer.h
|
||||||
)
|
)
|
||||||
FIND_PACKAGE(Threads REQUIRED)
|
FIND_PACKAGE(Threads REQUIRED)
|
||||||
LIST(APPEND telldus-service_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
LIST(APPEND telldus-service_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
@ -129,15 +139,27 @@ ELSEIF (WIN32) #### Windows ####
|
||||||
main_win.cpp
|
main_win.cpp
|
||||||
SettingsWinRegistry.cpp
|
SettingsWinRegistry.cpp
|
||||||
TelldusWinService_win.cpp
|
TelldusWinService_win.cpp
|
||||||
|
Messages.mc
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/Messages.rc
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/Messages.h
|
||||||
)
|
)
|
||||||
LIST(APPEND telldus-service_HDRS
|
LIST(APPEND telldus-service_HDRS
|
||||||
TelldusWinService_win.h
|
TelldusWinService_win.h
|
||||||
)
|
)
|
||||||
|
ADD_CUSTOM_COMMAND(
|
||||||
|
OUTPUT Messages.rc Messages.h
|
||||||
|
COMMAND mc.exe -u -r ${CMAKE_CURRENT_BINARY_DIR} -h ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Messages.mc
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Messages.mc
|
||||||
|
DEPENDS Messages.rc
|
||||||
|
COMMENT "Compiling Messages Resource"
|
||||||
|
)
|
||||||
|
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||||
|
|
||||||
ELSE (APPLE) #### Linux ####
|
ELSE (APPLE) #### Linux ####
|
||||||
SET(DEFAULT_FTDI_ENGINE "libftdi")
|
SET(DEFAULT_FTDI_ENGINE "libftdi")
|
||||||
FIND_LIBRARY(CONFUSE_LIBRARY confuse)
|
FIND_LIBRARY(CONFUSE_LIBRARY confuse)
|
||||||
ADD_DEFINITIONS( -D_CONFUSE )
|
ADD_DEFINITIONS( -D_CONFUSE )
|
||||||
|
ADD_DEFINITIONS( -D_LINUX )
|
||||||
|
|
||||||
SET( telldus-service_TARGET telldusd )
|
SET( telldus-service_TARGET telldusd )
|
||||||
LIST(APPEND telldus-service_SRCS
|
LIST(APPEND telldus-service_SRCS
|
||||||
|
|
|
@ -76,6 +76,7 @@ void ClientCommunicationHandler::parseMessage(const std::wstring &clientMessage,
|
||||||
if (function == L"tdTurnOn") {
|
if (function == L"tdTurnOn") {
|
||||||
int deviceId = TelldusCore::Message::takeInt(&msg);
|
int deviceId = TelldusCore::Message::takeInt(&msg);
|
||||||
(*intReturn) = d->deviceManager->doAction(deviceId, TELLSTICK_TURNON, 0);
|
(*intReturn) = d->deviceManager->doAction(deviceId, TELLSTICK_TURNON, 0);
|
||||||
|
|
||||||
} else if (function == L"tdTurnOff") {
|
} else if (function == L"tdTurnOff") {
|
||||||
int deviceId = TelldusCore::Message::takeInt(&msg);
|
int deviceId = TelldusCore::Message::takeInt(&msg);
|
||||||
(*intReturn) = d->deviceManager->doAction(deviceId, TELLSTICK_TURNOFF, 0);
|
(*intReturn) = d->deviceManager->doAction(deviceId, TELLSTICK_TURNOFF, 0);
|
||||||
|
@ -206,11 +207,6 @@ void ClientCommunicationHandler::parseMessage(const std::wstring &clientMessage,
|
||||||
std::wstring command = TelldusCore::Message::takeString(&msg);
|
std::wstring command = TelldusCore::Message::takeString(&msg);
|
||||||
int reserved = TelldusCore::Message::takeInt(&msg);
|
int reserved = TelldusCore::Message::takeInt(&msg);
|
||||||
(*intReturn) = d->deviceManager->sendRawCommand(command, reserved);
|
(*intReturn) = d->deviceManager->sendRawCommand(command, reserved);
|
||||||
EventUpdateData *eventData = new EventUpdateData();
|
|
||||||
eventData->messageType = L"TDRawDeviceEvent";
|
|
||||||
eventData->controllerId = -1;
|
|
||||||
eventData->eventValue = command;
|
|
||||||
d->deviceUpdateEvent->signal(eventData);
|
|
||||||
|
|
||||||
} else if (function == L"tdConnectTellStickController") {
|
} else if (function == L"tdConnectTellStickController") {
|
||||||
int vid = TelldusCore::Message::takeInt(&msg);
|
int vid = TelldusCore::Message::takeInt(&msg);
|
||||||
|
|
|
@ -91,46 +91,57 @@ void ConnectionListener::run() {
|
||||||
|
|
||||||
d->hEvent = CreateEvent(NULL, true, false, NULL);
|
d->hEvent = CreateEvent(NULL, true, false, NULL);
|
||||||
oOverlap.hEvent = d->hEvent;
|
oOverlap.hEvent = d->hEvent;
|
||||||
|
bool recreate = true;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
hPipe = CreateNamedPipe(
|
BOOL alreadyConnected = false;
|
||||||
(const wchar_t *)d->pipename.c_str(), // pipe name
|
if (recreate) {
|
||||||
PIPE_ACCESS_DUPLEX | // read/write access
|
hPipe = CreateNamedPipe(
|
||||||
FILE_FLAG_OVERLAPPED, //Overlapped mode
|
(const wchar_t *)d->pipename.c_str(), // pipe name
|
||||||
PIPE_TYPE_MESSAGE | // message type pipe
|
PIPE_ACCESS_DUPLEX | // read/write access
|
||||||
PIPE_READMODE_MESSAGE | // message-read mode
|
FILE_FLAG_OVERLAPPED, //Overlapped mode
|
||||||
PIPE_WAIT, // blocking mode
|
PIPE_TYPE_MESSAGE | // message type pipe
|
||||||
PIPE_UNLIMITED_INSTANCES, // max. instances
|
PIPE_READMODE_MESSAGE | // message-read mode
|
||||||
BUFSIZE, // output buffer size
|
PIPE_WAIT, // blocking mode
|
||||||
BUFSIZE, // input buffer size
|
PIPE_UNLIMITED_INSTANCES, // max. instances
|
||||||
0, // client time-out
|
BUFSIZE, // output buffer size
|
||||||
&d->sa); // default security attribute
|
BUFSIZE, // input buffer size
|
||||||
|
0, // client time-out
|
||||||
|
&d->sa); // default security attribute
|
||||||
|
|
||||||
if (hPipe == INVALID_HANDLE_VALUE) {
|
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||||
//TelldusCore::logMessage("Could not create named pipe");
|
return;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
ConnectNamedPipe(hPipe, &oOverlap);
|
||||||
|
alreadyConnected = GetLastError() == ERROR_PIPE_CONNECTED;
|
||||||
|
recreate = false;
|
||||||
}
|
}
|
||||||
|
if(!alreadyConnected){
|
||||||
|
DWORD result = WaitForSingleObject(oOverlap.hEvent, 1000);
|
||||||
|
if (!d->running) {
|
||||||
|
CancelIo(hPipe);
|
||||||
|
WaitForSingleObject(oOverlap.hEvent, INFINITE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result == WAIT_TIMEOUT){
|
||||||
|
//CloseHandle(hPipe);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BOOL connected = GetOverlappedResult(hPipe, &oOverlap, &cbBytesRead, false);
|
||||||
|
|
||||||
ConnectNamedPipe(hPipe, &oOverlap);
|
if (!connected) {
|
||||||
|
CloseHandle(hPipe);
|
||||||
DWORD result = WaitForSingleObject(oOverlap.hEvent, 1000);
|
return;
|
||||||
|
}
|
||||||
if (!d->running) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(result == WAIT_TIMEOUT){
|
|
||||||
CloseHandle(hPipe);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
BOOL connected = GetOverlappedResult(hPipe, &oOverlap, &cbBytesRead, false);
|
|
||||||
|
|
||||||
if (!connected) {
|
|
||||||
CloseHandle(hPipe);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
ConnectionListenerEventData *data = new ConnectionListenerEventData();
|
ConnectionListenerEventData *data = new ConnectionListenerEventData();
|
||||||
|
ResetEvent(oOverlap.hEvent);
|
||||||
data->socket = new TelldusCore::Socket(hPipe);
|
data->socket = new TelldusCore::Socket(hPipe);
|
||||||
d->waitEvent->signal(data);
|
d->waitEvent->signal(data);
|
||||||
|
|
||||||
|
recreate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(d->hEvent);
|
CloseHandle(d->hEvent);
|
||||||
|
|
|
@ -16,6 +16,7 @@ public:
|
||||||
|
|
||||||
virtual int firmwareVersion() = 0;
|
virtual int firmwareVersion() = 0;
|
||||||
virtual int send( const std::string &message ) = 0;
|
virtual int send( const std::string &message ) = 0;
|
||||||
|
virtual int reset() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Controller(int id, Event *event);
|
Controller(int id, Event *event);
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "Controller.h"
|
#include "Controller.h"
|
||||||
#include "Mutex.h"
|
#include "Mutex.h"
|
||||||
#include "TellStick.h"
|
#include "TellStick.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "../client/telldus-core.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -119,3 +121,47 @@ void ControllerManager::loadControllers() {
|
||||||
d->controllers[d->lastControllerId] = controller;
|
d->controllers[d->lastControllerId] = controller;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ControllerManager::queryControllerStatus(){
|
||||||
|
|
||||||
|
std::list<TellStick *> tellStickControllers;
|
||||||
|
|
||||||
|
{
|
||||||
|
TelldusCore::MutexLocker locker(&d->mutex);
|
||||||
|
for(ControllerMap::iterator it = d->controllers.begin(); it != d->controllers.end(); ++it) {
|
||||||
|
TellStick *tellstick = reinterpret_cast<TellStick*>(it->second);
|
||||||
|
if (tellstick) {
|
||||||
|
tellStickControllers.push_back(tellstick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reloadControllers = false;
|
||||||
|
std::string noop = "N+";
|
||||||
|
for(std::list<TellStick *>::iterator it = tellStickControllers.begin(); it != tellStickControllers.end(); ++it) {
|
||||||
|
int success = (*it)->send(noop);
|
||||||
|
if(success == TELLSTICK_ERROR_BROKEN_PIPE){
|
||||||
|
Log::warning("TellStick query: Error in communication with TellStick, resetting USB");
|
||||||
|
resetController(*it);
|
||||||
|
}
|
||||||
|
if(success == TELLSTICK_ERROR_BROKEN_PIPE || success == TELLSTICK_ERROR_NOT_FOUND){
|
||||||
|
reloadControllers = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!tellStickControllers.size() || reloadControllers){
|
||||||
|
//no tellstick at all found, or controller was reset
|
||||||
|
Log::debug("TellStick query: Rescanning USB ports"); //only log as debug, since this will happen all the time if no TellStick is connected
|
||||||
|
loadControllers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ControllerManager::resetController(Controller *controller) {
|
||||||
|
TellStick *tellstick = reinterpret_cast<TellStick*>(controller);
|
||||||
|
if (!tellstick) {
|
||||||
|
return true; //not tellstick, nothing to reset at the moment, just return true
|
||||||
|
}
|
||||||
|
int success = tellstick->reset();
|
||||||
|
deviceInsertedOrRemoved(tellstick->vid(), tellstick->pid(), tellstick->serial(), false); //remove from list and delete
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ public:
|
||||||
void deviceInsertedOrRemoved(int vid, int pid, const std::string &serial, bool inserted);
|
void deviceInsertedOrRemoved(int vid, int pid, const std::string &serial, bool inserted);
|
||||||
|
|
||||||
Controller *getBestControllerById(int id);
|
Controller *getBestControllerById(int id);
|
||||||
|
|
||||||
protected:
|
|
||||||
void loadControllers();
|
void loadControllers();
|
||||||
|
void queryControllerStatus();
|
||||||
|
int resetController(Controller *controller);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class PrivateData;
|
class PrivateData;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "Strings.h"
|
#include "Strings.h"
|
||||||
#include "Message.h"
|
#include "Message.h"
|
||||||
#include "common.h"
|
#include "Log.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -432,9 +432,31 @@ int DeviceManager::doAction(int deviceId, int action, unsigned char data){
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
Controller *controller = d->controllerManager->getBestControllerById(device->getPreferredControllerId());
|
Controller *controller = d->controllerManager->getBestControllerById(device->getPreferredControllerId());
|
||||||
|
if(!controller){
|
||||||
|
Log::warning("Trying to execute action, but no controller found. Rescanning USB ports");
|
||||||
|
//no controller found, scan for one, and retry once
|
||||||
|
d->controllerManager->loadControllers();
|
||||||
|
controller = d->controllerManager->getBestControllerById(device->getPreferredControllerId());
|
||||||
|
}
|
||||||
|
|
||||||
if(controller){
|
if(controller){
|
||||||
retval = device->doAction(action, data, controller);
|
retval = device->doAction(action, data, controller);
|
||||||
|
if(retval == TELLSTICK_ERROR_BROKEN_PIPE){
|
||||||
|
Log::warning("Error in communication with TellStick when executing action. Resetting USB");
|
||||||
|
d->controllerManager->resetController(controller);
|
||||||
|
}
|
||||||
|
if(retval == TELLSTICK_ERROR_BROKEN_PIPE || retval == TELLSTICK_ERROR_NOT_FOUND){
|
||||||
|
Log::warning("Rescanning USB ports");
|
||||||
|
d->controllerManager->loadControllers();
|
||||||
|
controller = d->controllerManager->getBestControllerById(device->getPreferredControllerId());
|
||||||
|
if(!controller){
|
||||||
|
Log::error("No contoller (TellStick) found, even after reset. Giving up.");
|
||||||
|
return TELLSTICK_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
retval = device->doAction(action, data, controller); //retry one more time
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Log::error("No contoller (TellStick) found after one retry. Giving up.");
|
||||||
return TELLSTICK_ERROR_NOT_FOUND;
|
return TELLSTICK_ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -479,7 +501,7 @@ int DeviceManager::doGroupAction(const std::wstring devices, const int action, c
|
||||||
deviceReturnValue = doAction(deviceId, action, data);
|
deviceReturnValue = doAction(deviceId, action, data);
|
||||||
}
|
}
|
||||||
else if(childType == TELLSTICK_TYPE_SCENE){
|
else if(childType == TELLSTICK_TYPE_SCENE){
|
||||||
deviceReturnValue = doGroupAction(DeviceManager::getDeviceParameter(deviceId, L"devices", L""), action, data, childType, deviceId, duplicateDeviceIds); //TODO make scenes (and test) infinite loops-safe
|
deviceReturnValue = doGroupAction(DeviceManager::getDeviceParameter(deviceId, L"devices", L""), action, data, childType, deviceId, duplicateDeviceIds); //TODO make scenes infinite loops-safe
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
//group (in group)
|
//group (in group)
|
||||||
|
@ -719,10 +741,29 @@ void DeviceManager::setSensorValueAndSignal( const std::string &dataType, int da
|
||||||
int DeviceManager::sendRawCommand(const std::wstring &command, int reserved){
|
int DeviceManager::sendRawCommand(const std::wstring &command, int reserved){
|
||||||
|
|
||||||
Controller *controller = d->controllerManager->getBestControllerById(-1);
|
Controller *controller = d->controllerManager->getBestControllerById(-1);
|
||||||
if(controller){
|
|
||||||
return controller->send(TelldusCore::wideToString(command));
|
if(!controller){
|
||||||
|
//no controller found, scan for one, and retry once
|
||||||
|
d->controllerManager->loadControllers();
|
||||||
|
controller = d->controllerManager->getBestControllerById(-1);
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
|
int retval = TELLSTICK_ERROR_UNKNOWN;
|
||||||
|
if(controller){
|
||||||
|
retval = controller->send(TelldusCore::wideToString(command));
|
||||||
|
if(retval == TELLSTICK_ERROR_BROKEN_PIPE){
|
||||||
|
d->controllerManager->resetController(controller);
|
||||||
|
}
|
||||||
|
if(retval == TELLSTICK_ERROR_BROKEN_PIPE || retval == TELLSTICK_ERROR_NOT_FOUND){
|
||||||
|
d->controllerManager->loadControllers();
|
||||||
|
controller = d->controllerManager->getBestControllerById(-1);
|
||||||
|
if(!controller){
|
||||||
|
return TELLSTICK_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
retval = controller->send(TelldusCore::wideToString(command)); //retry one more time
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
} else {
|
||||||
return TELLSTICK_ERROR_NOT_FOUND;
|
return TELLSTICK_ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,15 +51,17 @@ void EventHandler::signal(Event *) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventHandler::waitForAny() {
|
bool EventHandler::waitForAny() {
|
||||||
int result = WaitForMultipleObjects(d->eventCount, d->eventArray, FALSE, INFINITE);
|
|
||||||
|
while(1){
|
||||||
TelldusCore::MutexLocker locker(&d->mutex);
|
int result = WaitForMultipleObjects(d->eventCount, d->eventArray, FALSE, 1000);
|
||||||
if (result == WAIT_TIMEOUT) {
|
if (result == WAIT_TIMEOUT) {
|
||||||
return false;
|
continue;
|
||||||
|
}
|
||||||
|
TelldusCore::MutexLocker locker(&d->mutex);
|
||||||
|
int eventIndex = result - WAIT_OBJECT_0;
|
||||||
|
if (eventIndex >= d->eventCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
int eventIndex = result - WAIT_OBJECT_0;
|
|
||||||
if (eventIndex >= d->eventCount) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,10 +73,10 @@ void EventUpdateManager::run(){
|
||||||
|
|
||||||
void EventUpdateManager::sendMessageToClients(EventUpdateData *data){
|
void EventUpdateManager::sendMessageToClients(EventUpdateData *data){
|
||||||
|
|
||||||
|
int connected = 0;
|
||||||
for(SocketList::iterator it = d->clients.begin(); it != d->clients.end();){
|
for(SocketList::iterator it = d->clients.begin(); it != d->clients.end();){
|
||||||
|
|
||||||
if((*it)->isConnected()){
|
if((*it)->isConnected()){
|
||||||
|
connected++;
|
||||||
TelldusCore::Message msg;
|
TelldusCore::Message msg;
|
||||||
|
|
||||||
if(data->messageType == L"TDDeviceEvent"){
|
if(data->messageType == L"TDDeviceEvent"){
|
||||||
|
|
180
telldus-core/service/Log.cpp
Normal file
180
telldus-core/service/Log.cpp
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
#include "Log.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#if defined(_LINUX)
|
||||||
|
#include <syslog.h>
|
||||||
|
#elif defined(_WINDOWS)
|
||||||
|
#include <windows.h>
|
||||||
|
#include "Strings.h"
|
||||||
|
#include "Messages.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Log::PrivateData {
|
||||||
|
public:
|
||||||
|
PrivateData() : logOutput(Log::System), debug(false) {}
|
||||||
|
|
||||||
|
Log::LogOutput logOutput;
|
||||||
|
bool debug;
|
||||||
|
|
||||||
|
static Log *instance;
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
HANDLE eventSource;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
Log *Log::PrivateData::instance = 0;
|
||||||
|
|
||||||
|
Log::Log()
|
||||||
|
:d(new PrivateData)
|
||||||
|
{
|
||||||
|
#if defined(_LINUX)
|
||||||
|
setlogmask(LOG_UPTO(LOG_INFO));
|
||||||
|
openlog("telldusd", LOG_CONS, LOG_USER);
|
||||||
|
#elif defined(_MACOSX)
|
||||||
|
d->logOutput = Log::StdOut;
|
||||||
|
#elif defined(_WINDOWS)
|
||||||
|
//Add ourselves to the registy
|
||||||
|
HKEY hRegKey = NULL;
|
||||||
|
DWORD dwError = 0;
|
||||||
|
TCHAR filePath[MAX_PATH];
|
||||||
|
|
||||||
|
std::wstring path(L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\TelldusService");
|
||||||
|
dwError = RegCreateKey( HKEY_LOCAL_MACHINE, path.c_str(), &hRegKey );
|
||||||
|
|
||||||
|
GetModuleFileName( NULL, filePath, MAX_PATH );
|
||||||
|
dwError = RegSetValueEx( hRegKey, L"EventMessageFile", 0,
|
||||||
|
REG_EXPAND_SZ, (PBYTE) filePath,
|
||||||
|
(DWORD)(wcslen(filePath) + 1) * sizeof TCHAR );
|
||||||
|
|
||||||
|
DWORD dwTypes = LOG_DEBUG | LOG_NOTICE | LOG_WARNING | LOG_ERR;
|
||||||
|
dwError = RegSetValueEx( hRegKey, L"TypesSupported",
|
||||||
|
0, REG_DWORD, (LPBYTE) &dwTypes, sizeof dwTypes );
|
||||||
|
|
||||||
|
RegCloseKey(hRegKey);
|
||||||
|
|
||||||
|
d->eventSource = RegisterEventSource(NULL, L"TelldusService");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::~Log() {
|
||||||
|
#if defined(_LINUX)
|
||||||
|
closelog();
|
||||||
|
#elif defined(_WINDOWS)
|
||||||
|
if (d->eventSource != NULL) {
|
||||||
|
DeregisterEventSource(d->eventSource);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::destroy() {
|
||||||
|
if (PrivateData::instance == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete PrivateData::instance;
|
||||||
|
PrivateData::instance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::debug(const char *fmt, ...) {
|
||||||
|
Log *log = Log::instance();
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
log->message(Debug, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::notice(const char *fmt, ...) {
|
||||||
|
Log *log = Log::instance();
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
log->message(Notice, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::warning(const char *fmt, ...) {
|
||||||
|
Log *log = Log::instance();
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
log->message(Warning, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::error(const char *fmt, ...) {
|
||||||
|
Log *log = Log::instance();
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
log->message(Error, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::setDebug() {
|
||||||
|
Log *log = Log::instance();
|
||||||
|
log->d->debug = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::setLogOutput(LogOutput logOutput) {
|
||||||
|
#ifdef _MACOSX
|
||||||
|
//Always stdout
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
Log *log = Log::instance();
|
||||||
|
log->d->logOutput = logOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::message(Log::LogLevel logLevel, const char *format, va_list ap) const {
|
||||||
|
if (logLevel == Debug && d->debug == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (d->logOutput == StdOut) {
|
||||||
|
FILE *stream = stdout;
|
||||||
|
if (logLevel == Warning || logLevel == Error) {
|
||||||
|
stream = stderr;
|
||||||
|
}
|
||||||
|
vfprintf(stream, format, ap);
|
||||||
|
fprintf(stream, "\n");
|
||||||
|
fflush(stream);
|
||||||
|
} else {
|
||||||
|
#if defined(_LINUX)
|
||||||
|
switch (logLevel) {
|
||||||
|
case Debug:
|
||||||
|
vsyslog(LOG_DEBUG, format, ap);
|
||||||
|
break;
|
||||||
|
case Notice:
|
||||||
|
vsyslog(LOG_NOTICE, format, ap);
|
||||||
|
break;
|
||||||
|
case Warning:
|
||||||
|
vsyslog(LOG_WARNING, format, ap);
|
||||||
|
break;
|
||||||
|
case Error:
|
||||||
|
vsyslog(LOG_ERR, format, ap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#elif defined(_WINDOWS)
|
||||||
|
LPWSTR pInsertStrings[2] = {NULL, NULL};
|
||||||
|
std::wstring str = TelldusCore::charToWstring(TelldusCore::sformatf(format, ap).c_str());
|
||||||
|
pInsertStrings[0] = (LPWSTR)str.c_str();
|
||||||
|
|
||||||
|
switch (logLevel) {
|
||||||
|
case Debug:
|
||||||
|
ReportEvent(d->eventSource, EVENTLOG_SUCCESS, NULL, LOG_DEBUG, NULL, 1, 0, (LPCWSTR*)pInsertStrings, NULL);
|
||||||
|
break;
|
||||||
|
case Notice:
|
||||||
|
ReportEvent(d->eventSource, EVENTLOG_INFORMATION_TYPE, NULL, LOG_NOTICE, NULL, 1, 0, (LPCWSTR*)pInsertStrings, NULL);
|
||||||
|
break;
|
||||||
|
case Warning:
|
||||||
|
ReportEvent(d->eventSource, EVENTLOG_WARNING_TYPE, NULL, LOG_WARNING, NULL, 1, 0, (LPCWSTR*)pInsertStrings, NULL);
|
||||||
|
break;
|
||||||
|
case Error:
|
||||||
|
ReportEvent(d->eventSource, EVENTLOG_ERROR_TYPE, NULL, LOG_ERR, NULL, 1, 0, (LPCWSTR*)pInsertStrings, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log *Log::instance() {
|
||||||
|
if (PrivateData::instance == 0) {
|
||||||
|
PrivateData::instance = new Log();
|
||||||
|
}
|
||||||
|
return PrivateData::instance;
|
||||||
|
}
|
33
telldus-core/service/Log.h
Normal file
33
telldus-core/service/Log.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef LOG_H
|
||||||
|
#define LOG_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
class Log {
|
||||||
|
public:
|
||||||
|
enum LogLevel { Debug, Notice, Warning, Error };
|
||||||
|
enum LogOutput { StdOut, System };
|
||||||
|
virtual ~Log();
|
||||||
|
|
||||||
|
static void destroy();
|
||||||
|
|
||||||
|
static void debug(const char *fmt, ...);
|
||||||
|
static void notice(const char *fmt, ...);
|
||||||
|
static void warning(const char *fmt, ...);
|
||||||
|
static void error(const char *fmt, ...);
|
||||||
|
|
||||||
|
static void setDebug();
|
||||||
|
static void setLogOutput(LogOutput logOutput);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Log();
|
||||||
|
void message(LogLevel logLevel, const char *format, va_list ap) const;
|
||||||
|
static Log *instance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //LOG_H
|
BIN
telldus-core/service/Messages.mc
Normal file
BIN
telldus-core/service/Messages.mc
Normal file
Binary file not shown.
|
@ -5,11 +5,14 @@
|
||||||
#include "ProtocolBrateck.h"
|
#include "ProtocolBrateck.h"
|
||||||
#include "ProtocolComen.h"
|
#include "ProtocolComen.h"
|
||||||
#include "ProtocolEverflourish.h"
|
#include "ProtocolEverflourish.h"
|
||||||
|
#include "ProtocolFineoffset.h"
|
||||||
#include "ProtocolFuhaote.h"
|
#include "ProtocolFuhaote.h"
|
||||||
#include "ProtocolGroup.h"
|
#include "ProtocolGroup.h"
|
||||||
#include "ProtocolHasta.h"
|
#include "ProtocolHasta.h"
|
||||||
#include "ProtocolIkea.h"
|
#include "ProtocolIkea.h"
|
||||||
|
#include "ProtocolMandolyn.h"
|
||||||
#include "ProtocolNexa.h"
|
#include "ProtocolNexa.h"
|
||||||
|
#include "ProtocolOregon.h"
|
||||||
#include "ProtocolRisingSun.h"
|
#include "ProtocolRisingSun.h"
|
||||||
#include "ProtocolSartano.h"
|
#include "ProtocolSartano.h"
|
||||||
#include "ProtocolScene.h"
|
#include "ProtocolScene.h"
|
||||||
|
@ -195,10 +198,10 @@ std::list<std::string> Protocol::getParametersForProtocol(const std::wstring &pr
|
||||||
|
|
||||||
} else if (TelldusCore::comparei(protocolName, L"yidong")) {
|
} else if (TelldusCore::comparei(protocolName, L"yidong")) {
|
||||||
parameters.push_back("unit");
|
parameters.push_back("unit");
|
||||||
|
|
||||||
} else if (TelldusCore::comparei(protocolName, L"group")) {
|
} else if (TelldusCore::comparei(protocolName, L"group")) {
|
||||||
parameters.push_back("devices");
|
parameters.push_back("devices");
|
||||||
|
|
||||||
} else if (TelldusCore::comparei(protocolName, L"scene")) {
|
} else if (TelldusCore::comparei(protocolName, L"scene")) {
|
||||||
parameters.push_back("devices");
|
parameters.push_back("devices");
|
||||||
}
|
}
|
||||||
|
@ -209,7 +212,7 @@ std::list<std::string> Protocol::getParametersForProtocol(const std::wstring &pr
|
||||||
std::list<std::string> Protocol::decodeData(const std::string &fullData) {
|
std::list<std::string> Protocol::decodeData(const std::string &fullData) {
|
||||||
std::list<std::string> retval;
|
std::list<std::string> retval;
|
||||||
std::string decoded = "";
|
std::string decoded = "";
|
||||||
|
|
||||||
ControllerMessage dataMsg(fullData);
|
ControllerMessage dataMsg(fullData);
|
||||||
if( TelldusCore::comparei(dataMsg.protocol(), L"arctech") ) {
|
if( TelldusCore::comparei(dataMsg.protocol(), L"arctech") ) {
|
||||||
decoded = ProtocolNexa::decodeData(dataMsg);
|
decoded = ProtocolNexa::decodeData(dataMsg);
|
||||||
|
@ -231,12 +234,30 @@ std::list<std::string> Protocol::decodeData(const std::string &fullData) {
|
||||||
retval.push_back(decoded);
|
retval.push_back(decoded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(TelldusCore::comparei(dataMsg.protocol(), L"fineoffset") ) {
|
||||||
|
decoded = ProtocolFineoffset::decodeData(dataMsg);
|
||||||
|
if (decoded != "") {
|
||||||
|
retval.push_back(decoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(TelldusCore::comparei(dataMsg.protocol(), L"mandolyn") ) {
|
||||||
|
decoded = ProtocolMandolyn::decodeData(dataMsg);
|
||||||
|
if (decoded != "") {
|
||||||
|
retval.push_back(decoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(TelldusCore::comparei(dataMsg.protocol(), L"oregon") ) {
|
||||||
|
decoded = ProtocolOregon::decodeData(dataMsg);
|
||||||
|
if (decoded != "") {
|
||||||
|
retval.push_back(decoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if(TelldusCore::comparei(dataMsg.protocol(), L"x10") ) {
|
else if(TelldusCore::comparei(dataMsg.protocol(), L"x10") ) {
|
||||||
decoded = ProtocolX10::decodeData(dataMsg);
|
decoded = ProtocolX10::decodeData(dataMsg);
|
||||||
if (decoded != "") {
|
if (decoded != "") {
|
||||||
retval.push_back(decoded);
|
retval.push_back(decoded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
50
telldus-core/service/ProtocolFineoffset.cpp
Normal file
50
telldus-core/service/ProtocolFineoffset.cpp
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#include "ProtocolFineoffset.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string ProtocolFineoffset::decodeData(ControllerMessage &dataMsg)
|
||||||
|
{
|
||||||
|
std::string data = dataMsg.getParameter("data");
|
||||||
|
if (data.length() < 8) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t checksum = strtol(data.substr(data.length()-2).c_str(), NULL, 16);
|
||||||
|
data = data.substr(0, data.length()-2);
|
||||||
|
|
||||||
|
uint8_t humidity = strtol(data.substr(data.length()-2).c_str(), NULL, 16);
|
||||||
|
data = data.substr(0, data.length()-2);
|
||||||
|
|
||||||
|
uint16_t value = strtol(data.substr(data.length()-3).c_str(), NULL, 16);
|
||||||
|
double temperature = (value & 0x7FF)/10.0;
|
||||||
|
|
||||||
|
value >>= 11;
|
||||||
|
if (value & 1) {
|
||||||
|
temperature = -temperature;
|
||||||
|
}
|
||||||
|
data = data.substr(0, data.length()-3);
|
||||||
|
|
||||||
|
uint16_t id = strtol(data.c_str(), NULL, 16) & 0xFF;
|
||||||
|
|
||||||
|
std::stringstream retString;
|
||||||
|
retString << "class:sensor;protocol:fineoffset;id:" << id << ";model:";
|
||||||
|
|
||||||
|
if (humidity <= 100) {
|
||||||
|
retString << "temperaturehumidity;humidity:" << (int)humidity << ";";
|
||||||
|
} else if (humidity == 0xFF) {
|
||||||
|
retString << "temperature;";
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
retString << "temp:" << std::fixed << std::setprecision(1) << temperature << ";";
|
||||||
|
|
||||||
|
return retString.str();
|
||||||
|
}
|
13
telldus-core/service/ProtocolFineoffset.h
Normal file
13
telldus-core/service/ProtocolFineoffset.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef PROTOCOLFINEOFFSET_H
|
||||||
|
#define PROTOCOLFINEOFFSET_H
|
||||||
|
|
||||||
|
#include "ControllerMessage.h"
|
||||||
|
#include "Protocol.h"
|
||||||
|
|
||||||
|
class ProtocolFineoffset : public Protocol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string decodeData(ControllerMessage &dataMsg);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //PROTOCOLFINEOFFSET_H
|
44
telldus-core/service/ProtocolMandolyn.cpp
Normal file
44
telldus-core/service/ProtocolMandolyn.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include "ProtocolMandolyn.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string ProtocolMandolyn::decodeData(ControllerMessage &dataMsg)
|
||||||
|
{
|
||||||
|
std::string data = dataMsg.getParameter("data");
|
||||||
|
uint32_t value = strtol(data.c_str(), NULL, 16);
|
||||||
|
|
||||||
|
bool parity = value & 0x1;
|
||||||
|
value >>= 1;
|
||||||
|
|
||||||
|
double temp = (value & 0x7FFF) - 6400;
|
||||||
|
temp = temp/128.0;
|
||||||
|
value >>= 15;
|
||||||
|
|
||||||
|
uint8_t humidity = (value & 0x7F);
|
||||||
|
value >>= 7;
|
||||||
|
|
||||||
|
bool battOk = value & 0x1;
|
||||||
|
value >>= 3;
|
||||||
|
|
||||||
|
uint8_t channel = (value & 0x3)+1;
|
||||||
|
value >>= 2;
|
||||||
|
|
||||||
|
uint8_t house = value & 0xF;
|
||||||
|
|
||||||
|
std::stringstream retString;
|
||||||
|
retString << "class:sensor;protocol:mandolyn;id:"
|
||||||
|
<< house*10+channel
|
||||||
|
<< ";model:temperaturehumidity;"
|
||||||
|
<< "temp:" << std::fixed << std::setprecision(1) << temp
|
||||||
|
<< ";humidity:" << (int)humidity << ";";
|
||||||
|
|
||||||
|
return retString.str();
|
||||||
|
}
|
13
telldus-core/service/ProtocolMandolyn.h
Normal file
13
telldus-core/service/ProtocolMandolyn.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef PROTOCOLMANDOLYN_H
|
||||||
|
#define PROTOCOLMANDOLYN_H
|
||||||
|
|
||||||
|
#include "ControllerMessage.h"
|
||||||
|
#include "Protocol.h"
|
||||||
|
|
||||||
|
class ProtocolMandolyn : public Protocol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string decodeData(ControllerMessage &dataMsg);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //PROTOCOLMANDOLYN_H
|
|
@ -3,7 +3,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "TellStick.h"
|
#include "TellStick.h"
|
||||||
#include "Strings.h"
|
#include "Strings.h"
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
int ProtocolNexa::lastArctecCodeSwitchWasTurnOff=0; //TODO, always removing first turnon now, make more flexible (waveman too)
|
int ProtocolNexa::lastArctecCodeSwitchWasTurnOff=0; //TODO, always removing first turnon now, make more flexible (waveman too)
|
||||||
|
|
||||||
|
|
120
telldus-core/service/ProtocolOregon.cpp
Normal file
120
telldus-core/service/ProtocolOregon.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#include "ProtocolOregon.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string ProtocolOregon::decodeData(ControllerMessage &dataMsg)
|
||||||
|
{
|
||||||
|
std::string data = dataMsg.getParameter("data");
|
||||||
|
|
||||||
|
std::wstring model = dataMsg.model();
|
||||||
|
if (model.compare(L"0xEA4C") == 0) {
|
||||||
|
return decodeEA4C(data);
|
||||||
|
} else if (model.compare(L"0x1A2D") == 0) {
|
||||||
|
return decode1A2D(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ProtocolOregon::decodeEA4C(const std::string &data) {
|
||||||
|
uint64_t value = strtol(data.c_str(), NULL, 16);
|
||||||
|
|
||||||
|
uint8_t checksum = 0xE + 0xA + 0x4 + 0xC;
|
||||||
|
checksum -= (value & 0xF) * 0x10;
|
||||||
|
checksum -= 0xA;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
uint8_t checksumw = (value >> 4) & 0xF;
|
||||||
|
bool neg = value & (1 << 3);
|
||||||
|
checksum += (value & 0xF);
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
uint8_t temp2 = value & 0xF;
|
||||||
|
uint8_t temp1 = (value >> 4) & 0xF;
|
||||||
|
checksum += temp2 + temp1;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
uint8_t temp3 = (value >> 4) & 0xF;
|
||||||
|
checksum += (value & 0xF) + temp3;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
checksum += ((value >> 4) & 0xF) + (value & 0xF);
|
||||||
|
uint8_t address = value & 0xFF;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
checksum += ((value >> 4) & 0xF) + (value & 0xF);
|
||||||
|
uint8_t channel = (value >> 4) & 0x7;
|
||||||
|
|
||||||
|
if (checksum != checksumw) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
double temperature = ((temp1 * 100) + (temp2 * 10) + temp3)/10.0;
|
||||||
|
if (neg) {
|
||||||
|
temperature = -temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream retString;
|
||||||
|
retString << "class:sensor;protocol:oregon;model:EA4C;id:" << (int)address
|
||||||
|
<< ";temp:" << std::fixed << std::setprecision(1) << temperature << ";";
|
||||||
|
|
||||||
|
return retString.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ProtocolOregon::decode1A2D(const std::string &data) {
|
||||||
|
uint64_t value = strtol(data.c_str(), NULL, 16);
|
||||||
|
uint8_t checksum2 = value & 0xFF;
|
||||||
|
value >>= 8;
|
||||||
|
uint8_t checksum1 = value & 0xFF;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
uint8_t checksum = ((value >> 4) & 0xF) + (value & 0xF);
|
||||||
|
uint8_t hum1 = value & 0xF;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
checksum += ((value >> 4) & 0xF) + (value & 0xF);
|
||||||
|
uint8_t neg = value & (1 << 3);
|
||||||
|
uint8_t hum2 = (value >> 4) & 0xF;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
checksum += ((value >> 4) & 0xF) + (value & 0xF);
|
||||||
|
uint8_t temp2 = value & 0xF;
|
||||||
|
uint8_t temp1 = (value >> 4) & 0xF;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
checksum += ((value >> 4) & 0xF) + (value & 0xF);
|
||||||
|
uint8_t temp3 = (value >> 4) & 0xF;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
checksum += ((value >> 4) & 0xF) + (value & 0xF);
|
||||||
|
uint8_t address = value & 0xFF;
|
||||||
|
value >>= 8;
|
||||||
|
|
||||||
|
checksum += ((value >> 4) & 0xF) + (value & 0xF);
|
||||||
|
uint8_t channel = (value >> 4) & 0x7;
|
||||||
|
|
||||||
|
checksum += 0x1 + 0xA + 0x2 + 0xD - 0xA;
|
||||||
|
|
||||||
|
//TODO: Find out how checksum2 works
|
||||||
|
if (checksum != checksum1) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
double temperature = ((temp1 * 100) + (temp2 * 10) + temp3)/10.0;
|
||||||
|
if (neg) {
|
||||||
|
temperature = -temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream retString;
|
||||||
|
retString << "class:sensor;protocol:oregon;model:1A2D;id:" << (int)address
|
||||||
|
<< ";temp:" << std::fixed << std::setprecision(1) << temperature << ";";
|
||||||
|
|
||||||
|
return retString.str();
|
||||||
|
}
|
17
telldus-core/service/ProtocolOregon.h
Normal file
17
telldus-core/service/ProtocolOregon.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef PROTOCOLOREGON_H
|
||||||
|
#define PROTOCOLOREGON_H
|
||||||
|
|
||||||
|
#include "ControllerMessage.h"
|
||||||
|
#include "Protocol.h"
|
||||||
|
|
||||||
|
class ProtocolOregon : public Protocol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string decodeData(ControllerMessage &dataMsg);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::string decodeEA4C(const std::string &data);
|
||||||
|
static std::string decode1A2D(const std::string &data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //PROTOCOLOREGON_H
|
|
@ -375,6 +375,7 @@ bool readConfig(cfg_t **cfg) {
|
||||||
CFG_STR(const_cast<char *>("user"), const_cast<char *>("nobody"), CFGF_NONE),
|
CFG_STR(const_cast<char *>("user"), const_cast<char *>("nobody"), CFGF_NONE),
|
||||||
CFG_STR(const_cast<char *>("group"), const_cast<char *>("plugdev"), CFGF_NONE),
|
CFG_STR(const_cast<char *>("group"), const_cast<char *>("plugdev"), CFGF_NONE),
|
||||||
CFG_STR(const_cast<char *>("deviceNode"), const_cast<char *>("/dev/tellstick"), CFGF_NONE),
|
CFG_STR(const_cast<char *>("deviceNode"), const_cast<char *>("/dev/tellstick"), CFGF_NONE),
|
||||||
|
CFG_STR(const_cast<char *>("ignoreControllerConfirmation"), const_cast<char *>("false"), CFGF_NONE),
|
||||||
CFG_SEC(const_cast<char *>("device"), device_opts, CFGF_MULTI),
|
CFG_SEC(const_cast<char *>("device"), device_opts, CFGF_MULTI),
|
||||||
CFG_END()
|
CFG_END()
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
#include "Strings.h"
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
#include "../client/telldus-core.h"
|
#include "../client/telldus-core.h"
|
||||||
|
|
||||||
|
@ -93,9 +95,8 @@ int Settings::addDevice() {
|
||||||
DWORD dwDisp;
|
DWORD dwDisp;
|
||||||
intDeviceId = getNextDeviceId();
|
intDeviceId = getNextDeviceId();
|
||||||
|
|
||||||
std::wostringstream ssRegPath;
|
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
strCompleteRegPath.append(TelldusCore::intToWstring(intDeviceId));
|
||||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
|
||||||
|
|
||||||
if (RegCreateKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hk, &dwDisp)) {
|
if (RegCreateKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hk, &dwDisp)) {
|
||||||
//fail
|
//fail
|
||||||
|
@ -122,7 +123,7 @@ int Settings::getNextDeviceId() const {
|
||||||
DWORD dwLength;
|
DWORD dwLength;
|
||||||
DWORD nResult(0);
|
DWORD nResult(0);
|
||||||
|
|
||||||
long lngStatus = RegQueryValueEx(hk, L"LastUsedId", NULL, NULL, reinterpret_cast<LPBYTE>(&nResult), &dwLength); //(LPBYTE)Buff, &dwLength);
|
long lngStatus = RegQueryValueEx(hk, L"LastUsedId", NULL, NULL, reinterpret_cast<LPBYTE>(&nResult), &dwLength);
|
||||||
|
|
||||||
if(lngStatus == ERROR_SUCCESS){
|
if(lngStatus == ERROR_SUCCESS){
|
||||||
intReturn = nResult + 1;
|
intReturn = nResult + 1;
|
||||||
|
@ -143,9 +144,8 @@ int Settings::getNextDeviceId() const {
|
||||||
int Settings::removeDevice(int intDeviceId) {
|
int Settings::removeDevice(int intDeviceId) {
|
||||||
TelldusCore::MutexLocker locker(&mutex);
|
TelldusCore::MutexLocker locker(&mutex);
|
||||||
|
|
||||||
std::wostringstream ssRegPath;
|
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
strCompleteRegPath.append(TelldusCore::intToWstring(intDeviceId));
|
||||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
|
||||||
|
|
||||||
long lngSuccess = RegDeleteKey(d->rootKey, strCompleteRegPath.c_str());
|
long lngSuccess = RegDeleteKey(d->rootKey, strCompleteRegPath.c_str());
|
||||||
|
|
||||||
|
@ -157,13 +157,39 @@ int Settings::removeDevice(int intDeviceId) {
|
||||||
return TELLSTICK_ERROR_UNKNOWN;
|
return TELLSTICK_ERROR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::wstring Settings::getSetting(const std::wstring &strName) const{
|
||||||
|
std::wstring strReturn;
|
||||||
|
HKEY hk;
|
||||||
|
|
||||||
|
std::wstring strCompleteRegPath = d->strRegPath;
|
||||||
|
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_QUERY_VALUE, &hk);
|
||||||
|
|
||||||
|
if(lnExists == ERROR_SUCCESS){
|
||||||
|
wchar_t* Buff = new wchar_t[intMaxRegValueLength];
|
||||||
|
DWORD dwLength = sizeof(wchar_t)*intMaxRegValueLength;
|
||||||
|
long lngStatus = RegQueryValueEx(hk, strName.c_str(), NULL, NULL, (LPBYTE)Buff, &dwLength);
|
||||||
|
|
||||||
|
if(lngStatus == ERROR_MORE_DATA){
|
||||||
|
//The buffer is to small, recreate it
|
||||||
|
delete Buff;
|
||||||
|
Buff = new wchar_t[dwLength];
|
||||||
|
lngStatus = RegQueryValueEx(hk, strName.c_str(), NULL, NULL, (LPBYTE)Buff, &dwLength);
|
||||||
|
}
|
||||||
|
if (lngStatus == ERROR_SUCCESS) {
|
||||||
|
strReturn = Buff;
|
||||||
|
}
|
||||||
|
delete Buff;
|
||||||
|
}
|
||||||
|
RegCloseKey(hk);
|
||||||
|
return strReturn;
|
||||||
|
}
|
||||||
|
|
||||||
std::wstring Settings::getStringSetting(int intDeviceId, const std::wstring &name, bool parameter) const {
|
std::wstring Settings::getStringSetting(int intDeviceId, const std::wstring &name, bool parameter) const {
|
||||||
std::wstring strReturn;
|
std::wstring strReturn;
|
||||||
HKEY hk;
|
HKEY hk;
|
||||||
|
|
||||||
std::wostringstream ssRegPath;
|
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
strCompleteRegPath.append(TelldusCore::intToWstring(intDeviceId));
|
||||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
|
||||||
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_QUERY_VALUE, &hk);
|
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_QUERY_VALUE, &hk);
|
||||||
|
|
||||||
if(lnExists == ERROR_SUCCESS){
|
if(lnExists == ERROR_SUCCESS){
|
||||||
|
@ -191,9 +217,9 @@ int Settings::setStringSetting(int intDeviceId, const std::wstring &name, const
|
||||||
HKEY hk;
|
HKEY hk;
|
||||||
int ret = TELLSTICK_SUCCESS;
|
int ret = TELLSTICK_SUCCESS;
|
||||||
|
|
||||||
std::wostringstream ssRegPath;
|
std::wstring bla = TelldusCore::intToWstring(intDeviceId);
|
||||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
strCompleteRegPath.append(bla);
|
||||||
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_WRITE, &hk);
|
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_WRITE, &hk);
|
||||||
|
|
||||||
if (lnExists == ERROR_SUCCESS){
|
if (lnExists == ERROR_SUCCESS){
|
||||||
|
@ -223,9 +249,8 @@ int Settings::setIntSetting(int intDeviceId, const std::wstring &name, int value
|
||||||
int intReturn = TELLSTICK_ERROR_UNKNOWN;
|
int intReturn = TELLSTICK_ERROR_UNKNOWN;
|
||||||
HKEY hk;
|
HKEY hk;
|
||||||
|
|
||||||
std::wostringstream ssRegPath;
|
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
strCompleteRegPath.append(TelldusCore::intToWstring(intDeviceId));
|
||||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
|
||||||
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_WRITE, &hk);
|
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_WRITE, &hk);
|
||||||
if (lnExists == ERROR_SUCCESS) {
|
if (lnExists == ERROR_SUCCESS) {
|
||||||
DWORD dwVal = value;
|
DWORD dwVal = value;
|
||||||
|
|
|
@ -29,8 +29,12 @@ public:
|
||||||
|
|
||||||
virtual int firmwareVersion();
|
virtual int firmwareVersion();
|
||||||
virtual int pid() const;
|
virtual int pid() const;
|
||||||
|
virtual int vid() const;
|
||||||
|
virtual std::string serial() const;
|
||||||
|
|
||||||
bool isOpen() const;
|
bool isOpen() const;
|
||||||
bool isSameAsDescriptor(const TellStickDescriptor &d) const;
|
bool isSameAsDescriptor(const TellStickDescriptor &d) const;
|
||||||
|
virtual int reset();
|
||||||
virtual int send( const std::string &message );
|
virtual int send( const std::string &message );
|
||||||
bool stillConnected() const;
|
bool stillConnected() const;
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,11 @@
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
#include "TellStick.h"
|
#include "TellStick.h"
|
||||||
|
#include "common.h"
|
||||||
#include "Mutex.h"
|
#include "Mutex.h"
|
||||||
|
#include "Settings.h"
|
||||||
#include "Strings.h"
|
#include "Strings.h"
|
||||||
|
#include "Log.h"
|
||||||
#include "../client/telldus-core.h"
|
#include "../client/telldus-core.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -20,7 +23,7 @@
|
||||||
|
|
||||||
class TellStick::PrivateData {
|
class TellStick::PrivateData {
|
||||||
public:
|
public:
|
||||||
bool open, running;
|
bool open, running, ignoreControllerConfirmation;
|
||||||
int vid, pid, fwVersion;
|
int vid, pid, fwVersion;
|
||||||
std::string serial, message;
|
std::string serial, message;
|
||||||
FT_HANDLE ftHandle;
|
FT_HANDLE ftHandle;
|
||||||
|
@ -53,6 +56,8 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
||||||
d->pid = td.pid;
|
d->pid = td.pid;
|
||||||
d->fwVersion = 0;
|
d->fwVersion = 0;
|
||||||
d->serial = td.serial;
|
d->serial = td.serial;
|
||||||
|
Settings set;
|
||||||
|
d->ignoreControllerConfirmation = set.getSetting(L"ignoreControllerConfirmation")==L"true";
|
||||||
|
|
||||||
char *tempSerial = new char[td.serial.size()+1];
|
char *tempSerial = new char[td.serial.size()+1];
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
|
@ -61,6 +66,7 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
||||||
strcpy(tempSerial, td.serial.c_str());
|
strcpy(tempSerial, td.serial.c_str());
|
||||||
FT_SetVIDPID(td.vid, td.pid);
|
FT_SetVIDPID(td.vid, td.pid);
|
||||||
#endif
|
#endif
|
||||||
|
Log::notice("Connecting to TellStick (%X/%X) with serial %s", d->vid, d->pid, d->serial.c_str());
|
||||||
FT_STATUS ftStatus = FT_OpenEx(tempSerial, FT_OPEN_BY_SERIAL_NUMBER, &d->ftHandle);
|
FT_STATUS ftStatus = FT_OpenEx(tempSerial, FT_OPEN_BY_SERIAL_NUMBER, &d->ftHandle);
|
||||||
delete tempSerial;
|
delete tempSerial;
|
||||||
if (ftStatus == FT_OK) {
|
if (ftStatus == FT_OK) {
|
||||||
|
@ -76,10 +82,13 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
||||||
setBaud(4800);
|
setBaud(4800);
|
||||||
}
|
}
|
||||||
this->start();
|
this->start();
|
||||||
|
} else {
|
||||||
|
Log::warning("Failed to open TellStick");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TellStick::~TellStick() {
|
TellStick::~TellStick() {
|
||||||
|
Log::warning("Disconnected TellStick (%X/%X) with serial %s", d->vid, d->pid, d->serial.c_str());
|
||||||
if (d->running) {
|
if (d->running) {
|
||||||
TelldusCore::MutexLocker locker(&d->mutex);
|
TelldusCore::MutexLocker locker(&d->mutex);
|
||||||
d->running = false;
|
d->running = false;
|
||||||
|
@ -108,6 +117,14 @@ int TellStick::pid() const {
|
||||||
return d->pid;
|
return d->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TellStick::vid() const {
|
||||||
|
return d->vid;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TellStick::serial() const {
|
||||||
|
return d->serial;
|
||||||
|
}
|
||||||
|
|
||||||
bool TellStick::isOpen() const {
|
bool TellStick::isOpen() const {
|
||||||
return d->open;
|
return d->open;
|
||||||
}
|
}
|
||||||
|
@ -144,6 +161,18 @@ void TellStick::processData( const std::string &data ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TellStick::reset(){
|
||||||
|
#ifndef _WINDOWS
|
||||||
|
return TELLSTICK_SUCCESS; //nothing to be done on other platforms
|
||||||
|
#else
|
||||||
|
int success = FT_CyclePort( d->ftHandle );
|
||||||
|
if(success == FT_OK){
|
||||||
|
return TELLSTICK_SUCCESS;
|
||||||
|
}
|
||||||
|
return TELLSTICK_ERROR_UNKNOWN;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void TellStick::run() {
|
void TellStick::run() {
|
||||||
d->running = true;
|
d->running = true;
|
||||||
DWORD dwBytesInQueue = 0;
|
DWORD dwBytesInQueue = 0;
|
||||||
|
@ -186,8 +215,7 @@ int TellStick::send( const std::string &strMessage ) {
|
||||||
if (!d->open) {
|
if (!d->open) {
|
||||||
return TELLSTICK_ERROR_NOT_FOUND;
|
return TELLSTICK_ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
bool c = true;
|
|
||||||
|
|
||||||
//This lock does two things
|
//This lock does two things
|
||||||
// 1 Prevents two calls from different threads to this function
|
// 1 Prevents two calls from different threads to this function
|
||||||
// 2 Prevents our running thread from receiving the data we are interested in here
|
// 2 Prevents our running thread from receiving the data we are interested in here
|
||||||
|
@ -205,26 +233,39 @@ int TellStick::send( const std::string &strMessage ) {
|
||||||
FT_STATUS ftStatus;
|
FT_STATUS ftStatus;
|
||||||
ftStatus = FT_Write(d->ftHandle, tempMessage, (DWORD)strMessage.length(), &bytesWritten);
|
ftStatus = FT_Write(d->ftHandle, tempMessage, (DWORD)strMessage.length(), &bytesWritten);
|
||||||
free(tempMessage);
|
free(tempMessage);
|
||||||
|
|
||||||
|
if(ftStatus != FT_OK){
|
||||||
|
Log::debug("Broken pipe on send");
|
||||||
|
return TELLSTICK_ERROR_BROKEN_PIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strMessage.compare("N+") == 0 && ((pid() == 0x0C31 && firmwareVersion() < 5) || (pid() == 0x0C30 && firmwareVersion() < 6))){
|
||||||
|
//these firmware versions doesn't implement ack to noop, just check that the noop can be sent correctly
|
||||||
|
return TELLSTICK_SUCCESS;
|
||||||
|
}
|
||||||
|
if(d->ignoreControllerConfirmation){
|
||||||
|
//wait for TellStick to finish its air-sending
|
||||||
|
msleep(1000);
|
||||||
|
return TELLSTICK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
while(c) {
|
while(1) {
|
||||||
ftStatus = FT_Read(d->ftHandle,&in,1,&bytesRead);
|
ftStatus = FT_Read(d->ftHandle,&in,1,&bytesRead);
|
||||||
if (ftStatus == FT_OK) {
|
if (ftStatus == FT_OK) {
|
||||||
if (bytesRead == 1) {
|
if (bytesRead == 1) {
|
||||||
if (in == '\n') {
|
if (in == '\n') {
|
||||||
break;
|
return TELLSTICK_SUCCESS;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else { //Timeout
|
} else { //Timeout
|
||||||
c = false;
|
return TELLSTICK_ERROR_COMMUNICATION;
|
||||||
}
|
}
|
||||||
} else { //Error
|
} else { //Error
|
||||||
c = false;
|
Log::debug("Broken pipe on read");
|
||||||
|
return TELLSTICK_ERROR_BROKEN_PIPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c) {
|
|
||||||
return TELLSTICK_ERROR_COMMUNICATION;
|
|
||||||
}
|
|
||||||
return TELLSTICK_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TellStick::stillConnected() const {
|
bool TellStick::stillConnected() const {
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <ftdi.h>
|
#include <ftdi.h>
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "Mutex.h"
|
#include "Mutex.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "Settings.h"
|
||||||
#include "Strings.h"
|
#include "Strings.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
@ -31,7 +33,7 @@ typedef int DWORD;
|
||||||
|
|
||||||
class TellStick::PrivateData {
|
class TellStick::PrivateData {
|
||||||
public:
|
public:
|
||||||
bool open;
|
bool open, ignoreControllerConfirmation;
|
||||||
int vid, pid, fwVersion;
|
int vid, pid, fwVersion;
|
||||||
std::string serial, message;
|
std::string serial, message;
|
||||||
ftdi_context ftHandle;
|
ftdi_context ftHandle;
|
||||||
|
@ -51,9 +53,13 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
||||||
d->serial = td.serial;
|
d->serial = td.serial;
|
||||||
d->running = false;
|
d->running = false;
|
||||||
|
|
||||||
|
Settings set;
|
||||||
|
d->ignoreControllerConfirmation = set.getSetting(L"ignoreControllerConfirmation")==L"true";
|
||||||
|
|
||||||
ftdi_init(&d->ftHandle);
|
ftdi_init(&d->ftHandle);
|
||||||
ftdi_set_interface(&d->ftHandle, INTERFACE_ANY);
|
ftdi_set_interface(&d->ftHandle, INTERFACE_ANY);
|
||||||
|
|
||||||
|
Log::notice("Connecting to TellStick (%X/%X) with serial %s", d->vid, d->pid, d->serial.c_str());
|
||||||
int ret = ftdi_usb_open_desc(&d->ftHandle, td.vid, td.pid, NULL, td.serial.c_str());
|
int ret = ftdi_usb_open_desc(&d->ftHandle, td.vid, td.pid, NULL, td.serial.c_str());
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ftdi_deinit(&d->ftHandle);
|
ftdi_deinit(&d->ftHandle);
|
||||||
|
@ -62,6 +68,7 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
||||||
d->open = true;
|
d->open = true;
|
||||||
ftdi_usb_reset( &d->ftHandle );
|
ftdi_usb_reset( &d->ftHandle );
|
||||||
ftdi_disable_bitbang( &d->ftHandle );
|
ftdi_disable_bitbang( &d->ftHandle );
|
||||||
|
ftdi_set_latency_timer(&d->ftHandle, 16);
|
||||||
|
|
||||||
if (d->open) {
|
if (d->open) {
|
||||||
|
|
||||||
|
@ -71,10 +78,13 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
||||||
this->setBaud(4800);
|
this->setBaud(4800);
|
||||||
}
|
}
|
||||||
this->start();
|
this->start();
|
||||||
|
} else {
|
||||||
|
Log::warning("Failed to open TellStick");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TellStick::~TellStick() {
|
TellStick::~TellStick() {
|
||||||
|
Log::warning("Disconnected TellStick (%X/%X) with serial %s", d->vid, d->pid, d->serial.c_str());
|
||||||
if (d->running) {
|
if (d->running) {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
@ -94,6 +104,14 @@ int TellStick::pid() const {
|
||||||
return d->pid;
|
return d->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TellStick::vid() const {
|
||||||
|
return d->vid;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TellStick::serial() const {
|
||||||
|
return d->serial;
|
||||||
|
}
|
||||||
|
|
||||||
bool TellStick::isOpen() const {
|
bool TellStick::isOpen() const {
|
||||||
return d->open;
|
return d->open;
|
||||||
}
|
}
|
||||||
|
@ -130,6 +148,14 @@ void TellStick::processData( const std::string &data ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TellStick::reset(){
|
||||||
|
int success = ftdi_usb_reset( &d->ftHandle );
|
||||||
|
if(success < 0){
|
||||||
|
return TELLSTICK_ERROR_UNKNOWN; //-1 = FTDI reset failed, -2 = USB device unavailable
|
||||||
|
}
|
||||||
|
return TELLSTICK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
void TellStick::run() {
|
void TellStick::run() {
|
||||||
int dwBytesRead = 0;
|
int dwBytesRead = 0;
|
||||||
unsigned char buf[1024]; // = 0;
|
unsigned char buf[1024]; // = 0;
|
||||||
|
@ -186,33 +212,44 @@ int TellStick::send( const std::string &strMessage ) {
|
||||||
if(ret < 0) {
|
if(ret < 0) {
|
||||||
c = false;
|
c = false;
|
||||||
} else if(ret != strMessage.length()) {
|
} else if(ret != strMessage.length()) {
|
||||||
fprintf(stderr, "weird send length? retval %i instead of %d\n",
|
Log::debug("Weird send length? retval %i instead of %d\n", ret, (int)strMessage.length());
|
||||||
ret, (int)strMessage.length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] tempMessage;
|
delete[] tempMessage;
|
||||||
|
|
||||||
int retrycnt = 200;
|
if(!c){
|
||||||
|
Log::debug("Broken pipe on send");
|
||||||
|
return TELLSTICK_ERROR_BROKEN_PIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strMessage.compare("N+") == 0 && ((pid() == 0x0C31 && firmwareVersion() < 5) || (pid() == 0x0C30 && firmwareVersion() < 6))){
|
||||||
|
//these firmware versions doesn't implement ack to noop, just check that the noop can be sent correctly
|
||||||
|
return TELLSTICK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d->ignoreControllerConfirmation){
|
||||||
|
//allow TellStick to finish its air-sending
|
||||||
|
msleep(1000);
|
||||||
|
return TELLSTICK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retrycnt = 250;
|
||||||
unsigned char in;
|
unsigned char in;
|
||||||
while(c && --retrycnt) {
|
while(--retrycnt) {
|
||||||
ret = ftdi_read_data( &d->ftHandle, &in, 1);
|
ret = ftdi_read_data( &d->ftHandle, &in, 1);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
if (in == '\n') {
|
if (in == '\n') {
|
||||||
break;
|
return TELLSTICK_SUCCESS;
|
||||||
}
|
}
|
||||||
} else if(ret == 0) { // No data available
|
} else if(ret == 0) { // No data available
|
||||||
usleep(100);
|
usleep(100);
|
||||||
} else { //Error
|
} else { //Error
|
||||||
c = false;
|
Log::debug("Broken pipe on read");
|
||||||
|
return TELLSTICK_ERROR_BROKEN_PIPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!retrycnt) {
|
|
||||||
c = false;
|
return TELLSTICK_ERROR_COMMUNICATION;
|
||||||
}
|
|
||||||
if (!c) {
|
|
||||||
return TELLSTICK_ERROR_COMMUNICATION;
|
|
||||||
}
|
|
||||||
return TELLSTICK_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TellStick::setBaud(int baud) {
|
void TellStick::setBaud(int baud) {
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include "ControllerManager.h"
|
#include "ControllerManager.h"
|
||||||
#include "ControllerListener.h"
|
#include "ControllerListener.h"
|
||||||
#include "EventUpdateManager.h"
|
#include "EventUpdateManager.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
@ -39,6 +41,10 @@ void TelldusMain::deviceInsertedOrRemoved(int vid, int pid, bool inserted) {
|
||||||
void TelldusMain::start(void) {
|
void TelldusMain::start(void) {
|
||||||
EventRef clientEvent = d->eventHandler.addEvent();
|
EventRef clientEvent = d->eventHandler.addEvent();
|
||||||
EventRef dataEvent = d->eventHandler.addEvent();
|
EventRef dataEvent = d->eventHandler.addEvent();
|
||||||
|
EventRef janitor = d->eventHandler.addEvent(); //Used for regular cleanups
|
||||||
|
Timer supervisor(janitor); //Tells the janitor to go back to work
|
||||||
|
supervisor.setInterval(60); //Once every minute
|
||||||
|
supervisor.start();
|
||||||
|
|
||||||
ControllerManager controllerManager(dataEvent.get());
|
ControllerManager controllerManager(dataEvent.get());
|
||||||
EventUpdateManager eventUpdateManager;
|
EventUpdateManager eventUpdateManager;
|
||||||
|
@ -101,7 +107,16 @@ void TelldusMain::start(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (janitor->isSignaled()) {
|
||||||
|
//Clear all of them if there is more than one
|
||||||
|
while(janitor->isSignaled()) {
|
||||||
|
janitor->popSignal();
|
||||||
|
}
|
||||||
|
controllerManager.queryControllerStatus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
supervisor.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TelldusMain::stop(void){
|
void TelldusMain::stop(void){
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "TelldusWinService_win.h"
|
#include "TelldusWinService_win.h"
|
||||||
#include "TelldusMain.h"
|
#include "TelldusMain.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
#include <Dbt.h>
|
#include <Dbt.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -111,6 +112,13 @@ DWORD WINAPI TelldusWinService::serviceControlHandler( DWORD controlCode, DWORD
|
||||||
void WINAPI TelldusWinService::serviceMain( DWORD argc, TCHAR* argv[] ) {
|
void WINAPI TelldusWinService::serviceMain( DWORD argc, TCHAR* argv[] ) {
|
||||||
TelldusWinService instance;
|
TelldusWinService instance;
|
||||||
|
|
||||||
|
//Enable debug if we hade this supplied
|
||||||
|
for(unsigned int i = 1; i < argc; ++i) {
|
||||||
|
if (wcscmp(argv[i], L"--debug") == 0) {
|
||||||
|
Log::setDebug();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// initialise service status
|
// initialise service status
|
||||||
instance.serviceStatus.dwServiceType = SERVICE_WIN32;
|
instance.serviceStatus.dwServiceType = SERVICE_WIN32;
|
||||||
instance.serviceStatus.dwCurrentState = SERVICE_STOPPED;
|
instance.serviceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||||
|
@ -140,8 +148,13 @@ void WINAPI TelldusWinService::serviceMain( DWORD argc, TCHAR* argv[] ) {
|
||||||
devInterface.dbcc_classguid = GUID_DEVINTERFACE_USBRAW;
|
devInterface.dbcc_classguid = GUID_DEVINTERFACE_USBRAW;
|
||||||
HDEVNOTIFY deviceNotificationHandle = RegisterDeviceNotificationW(instance.serviceStatusHandle, &devInterface, DEVICE_NOTIFY_SERVICE_HANDLE);
|
HDEVNOTIFY deviceNotificationHandle = RegisterDeviceNotificationW(instance.serviceStatusHandle, &devInterface, DEVICE_NOTIFY_SERVICE_HANDLE);
|
||||||
|
|
||||||
|
Log::notice("TelldusService started");
|
||||||
|
|
||||||
//Start our main-loop
|
//Start our main-loop
|
||||||
instance.tm->start();
|
instance.tm->start();
|
||||||
|
|
||||||
|
Log::notice("TelldusService stopping");
|
||||||
|
Log::destroy();
|
||||||
|
|
||||||
// service was stopped
|
// service was stopped
|
||||||
instance.serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
instance.serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
||||||
|
|
114
telldus-core/service/Timer.cpp
Normal file
114
telldus-core/service/Timer.cpp
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Mutex.h"
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Timer::PrivateData {
|
||||||
|
public:
|
||||||
|
PrivateData() : interval(0), running(false) {}
|
||||||
|
EventRef event;
|
||||||
|
int interval;
|
||||||
|
bool running;
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
HANDLE cond;
|
||||||
|
TelldusCore::Mutex mutex;
|
||||||
|
#else
|
||||||
|
pthread_mutex_t waitMutex;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
Timer::Timer(EventRef event)
|
||||||
|
:TelldusCore::Thread(), d(new PrivateData)
|
||||||
|
{
|
||||||
|
d->event = event;
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
d->cond = CreateEventW(NULL, false, false, NULL);
|
||||||
|
#else
|
||||||
|
pthread_cond_init(&d->cond, NULL);
|
||||||
|
pthread_mutex_init(&d->waitMutex, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer::~Timer() {
|
||||||
|
this->stop();
|
||||||
|
this->wait();
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
#else
|
||||||
|
pthread_mutex_destroy(&d->waitMutex);
|
||||||
|
pthread_cond_destroy(&d->cond);
|
||||||
|
delete d;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::setInterval(int sec) {
|
||||||
|
d->interval = sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::stop() {
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
TelldusCore::MutexLocker(&d->mutex);
|
||||||
|
d->running = false;
|
||||||
|
SetEvent(d->cond);
|
||||||
|
#else
|
||||||
|
//Signal event
|
||||||
|
pthread_mutex_lock(&d->waitMutex);
|
||||||
|
if (d->running) {
|
||||||
|
d->running = false;
|
||||||
|
pthread_cond_signal(&d->cond);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&d->waitMutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::run() {
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
int interval = 0;
|
||||||
|
{
|
||||||
|
TelldusCore::MutexLocker(&d->mutex);
|
||||||
|
d->running = true;
|
||||||
|
interval = d->interval*1000;
|
||||||
|
}
|
||||||
|
while(1) {
|
||||||
|
DWORD retval = WaitForSingleObject(d->cond, interval);
|
||||||
|
if (retval == WAIT_TIMEOUT) {
|
||||||
|
d->event->signal();
|
||||||
|
}
|
||||||
|
TelldusCore::MutexLocker(&d->mutex);
|
||||||
|
if (!d->running) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
struct timespec ts;
|
||||||
|
struct timeval tp;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&d->waitMutex);
|
||||||
|
d->running = true;
|
||||||
|
pthread_mutex_unlock(&d->waitMutex);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
int rc = gettimeofday(&tp, NULL);
|
||||||
|
|
||||||
|
ts.tv_sec = tp.tv_sec;
|
||||||
|
ts.tv_nsec = tp.tv_usec * 1000;
|
||||||
|
ts.tv_sec += d->interval;
|
||||||
|
|
||||||
|
pthread_mutex_lock( &d->waitMutex );
|
||||||
|
if (d->running) {
|
||||||
|
rc = pthread_cond_timedwait(&d->cond, &d->waitMutex, &ts);
|
||||||
|
} else {
|
||||||
|
pthread_mutex_unlock( &d->waitMutex );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock( &d->waitMutex );
|
||||||
|
if (rc == ETIMEDOUT) {
|
||||||
|
d->event->signal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
24
telldus-core/service/Timer.h
Normal file
24
telldus-core/service/Timer.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef TIMER_H
|
||||||
|
#define TIMER_H
|
||||||
|
|
||||||
|
#include "Event.h"
|
||||||
|
#include "Thread.h"
|
||||||
|
|
||||||
|
class Timer : public TelldusCore::Thread {
|
||||||
|
public:
|
||||||
|
Timer(EventRef event);
|
||||||
|
virtual ~Timer();
|
||||||
|
|
||||||
|
void setInterval(int sec);
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //TIMER_H
|
|
@ -1,16 +1,16 @@
|
||||||
#include "TelldusMain.h"
|
#include "TelldusMain.h"
|
||||||
|
#include "Log.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
TelldusMain tm;
|
TelldusMain tm;
|
||||||
|
|
||||||
void shutdownHandler(int onSignal) {
|
void shutdownHandler(int onSignal) {
|
||||||
printf("Shutting down\n");
|
Log::notice("Shutting down");
|
||||||
tm.stop();
|
tm.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sigpipeHandler(int onSignal) {
|
void sigpipeHandler(int onSignal) {
|
||||||
printf("SIGPIPE received\n");
|
Log::notice("SIGPIPE received");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
@ -19,7 +19,10 @@ int main(int argc, char **argv) {
|
||||||
signal(SIGINT, shutdownHandler);
|
signal(SIGINT, shutdownHandler);
|
||||||
signal(SIGPIPE, sigpipeHandler);
|
signal(SIGPIPE, sigpipeHandler);
|
||||||
|
|
||||||
|
Log::notice("telldusd started");
|
||||||
tm.start();
|
tm.start();
|
||||||
printf("telldusd stopped gracefully\n");
|
Log::notice("telldusd stopped gracefully");
|
||||||
|
|
||||||
|
Log::destroy();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <syslog.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
@ -12,6 +11,7 @@
|
||||||
|
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "Strings.h"
|
#include "Strings.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
#define DAEMON_NAME "telldusd"
|
#define DAEMON_NAME "telldusd"
|
||||||
#define PID_FILE "/var/run/" DAEMON_NAME ".pid"
|
#define PID_FILE "/var/run/" DAEMON_NAME ".pid"
|
||||||
|
@ -21,19 +21,19 @@ TelldusMain tm;
|
||||||
void signalHandler(int sig) {
|
void signalHandler(int sig) {
|
||||||
switch(sig) {
|
switch(sig) {
|
||||||
case SIGHUP:
|
case SIGHUP:
|
||||||
syslog(LOG_WARNING, "Received SIGHUP signal.");
|
Log::warning("Received SIGHUP signal.");
|
||||||
break;
|
break;
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
syslog(LOG_WARNING, "Received SIGTERM or SIGINT signal.");
|
Log::warning("Received SIGTERM or SIGINT signal.");
|
||||||
syslog(LOG_WARNING, "Shutting down");
|
Log::warning("Shutting down");
|
||||||
tm.stop();
|
tm.stop();
|
||||||
break;
|
break;
|
||||||
case SIGPIPE:
|
case SIGPIPE:
|
||||||
syslog(LOG_WARNING, "Received SIGPIPE signal.");
|
Log::warning("Received SIGPIPE signal.");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
syslog(LOG_WARNING, "Unhandled signal (%d) %s", sig, strsignal(sig));
|
Log::warning("Unhandled signal (%d) %s", sig, strsignal(sig));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,17 +46,19 @@ int main(int argc, char **argv) {
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
if (strcmp(argv[i], "--nodaemon") == 0) {
|
if (strcmp(argv[i], "--nodaemon") == 0) {
|
||||||
deamonize = false;
|
deamonize = false;
|
||||||
}
|
Log::setLogOutput(Log::StdOut);
|
||||||
if (strcmp(argv[i], "--help") == 0) {
|
} else if (strcmp(argv[i], "--help") == 0) {
|
||||||
printf("Telldus TellStick background service\n\nStart with --nodaemon to not run as daemon\n\n");
|
printf("Telldus TellStick background service\n\nStart with --nodaemon to not run as daemon\n\n");
|
||||||
printf("Report bugs to <info.tech@telldus.com>\n");
|
printf("Report bugs to <info.tech@telldus.com>\n");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
} else if (strcmp(argv[i], "--version") == 0) {
|
||||||
if (strcmp(argv[i], "--version") == 0) {
|
|
||||||
printf("telldusd " VERSION "\n\n");
|
printf("telldusd " VERSION "\n\n");
|
||||||
printf("Copyright (C) 2011 Telldus Technologies AB\n\n");
|
printf("Copyright (C) 2011 Telldus Technologies AB\n\n");
|
||||||
printf("Written by Micke Prag <micke.prag@telldus.se>\n");
|
printf("Written by Micke Prag <micke.prag@telldus.se>\n");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
} else {
|
||||||
|
printf("Unknown option %s\n", argv[i]);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,17 +78,14 @@ int main(int argc, char **argv) {
|
||||||
fprintf(fd,"%d\n",pid);
|
fprintf(fd,"%d\n",pid);
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
} else {
|
} else {
|
||||||
syslog(LOG_ERR, "Could not open pid file %s: %s", PID_FILE, strerror(errno));
|
Log::error("Could not open pid file %s: %s", PID_FILE, strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setlogmask(LOG_UPTO(LOG_INFO));
|
Log::notice("%s daemon starting up", DAEMON_NAME);
|
||||||
openlog(DAEMON_NAME, LOG_CONS, LOG_USER);
|
|
||||||
|
|
||||||
syslog(LOG_NOTICE, "%s daemon starting up", DAEMON_NAME);
|
|
||||||
|
|
||||||
if (deamonize) {
|
if (deamonize) {
|
||||||
/* Change the file mode mask */
|
/* Change the file mode mask */
|
||||||
|
@ -115,14 +114,14 @@ int main(int argc, char **argv) {
|
||||||
if (grp) {
|
if (grp) {
|
||||||
setgid(grp->gr_gid);
|
setgid(grp->gr_gid);
|
||||||
} else {
|
} else {
|
||||||
syslog(LOG_WARNING, "Group %s could not be found", group.c_str());
|
Log::warning("Group %s could not be found", group.c_str());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
struct passwd *pw = getpwnam(user.c_str());
|
struct passwd *pw = getpwnam(user.c_str());
|
||||||
if (pw) {
|
if (pw) {
|
||||||
setuid( pw->pw_uid );
|
setuid( pw->pw_uid );
|
||||||
} else {
|
} else {
|
||||||
syslog(LOG_WARNING, "User %s could not be found", user.c_str());
|
Log::warning("User %s could not be found", user.c_str());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,6 +138,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
tm.start();
|
tm.start();
|
||||||
|
|
||||||
syslog(LOG_NOTICE, "%s daemon exited", DAEMON_NAME);
|
Log::notice("%s daemon exited", DAEMON_NAME);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
user = "nobody"
|
user = "nobody"
|
||||||
group = "plugdev"
|
group = "plugdev"
|
||||||
|
ignoreControllerConfirmation = "false"
|
||||||
device {
|
device {
|
||||||
id = 1
|
id = 1
|
||||||
name = "Example device"
|
name = "Example device"
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
ID_VENDOR_ID=="1781", SUBSYSTEM=="usb", ACTION=="add", MODE="664", GROUP="plugdev" RUN+="${CMAKE_INSTALL_PREFIX}/share/telldus-core/helpers/udev.sh"
|
ATTRS{idVendor}=="1781", SUBSYSTEM=="usb", ACTION=="add", MODE="664", GROUP="plugdev" RUN+="${CMAKE_INSTALL_PREFIX}/share/telldus-core/helpers/udev.sh"
|
||||||
ID_VENDOR_ID=="1781", SUBSYSTEM=="usb", ACTION=="remove" RUN+="${CMAKE_INSTALL_PREFIX}/share/telldus-core/helpers/udev.sh"
|
ENV{ID_VENDOR_ID}=="1781", SUBSYSTEM=="usb", ACTION=="remove" RUN+="${CMAKE_INSTALL_PREFIX}/share/telldus-core/helpers/udev.sh"
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctime>
|
||||||
#include "../client/telldus-core.h"
|
#include "../client/telldus-core.h"
|
||||||
|
|
||||||
const int SUPPORTED_METHODS =
|
const int SUPPORTED_METHODS =
|
||||||
|
@ -21,7 +22,7 @@ void print_usage( char *name ) {
|
||||||
printf(" [ --raw input ]\n");
|
printf(" [ --raw input ]\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" --list (-l short option)\n");
|
printf(" --list (-l short option)\n");
|
||||||
printf(" List currently configured devices.\n");
|
printf(" List currently configured devices and all discovered sensors.\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" --help (-h short option)\n");
|
printf(" --help (-h short option)\n");
|
||||||
printf(" Shows this screen.\n");
|
printf(" Shows this screen.\n");
|
||||||
|
@ -77,6 +78,7 @@ void print_version() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_device( int index ) {
|
void print_device( int index ) {
|
||||||
|
tdInit();
|
||||||
int intId = tdGetDeviceId(index);
|
int intId = tdGetDeviceId(index);
|
||||||
char *name = tdGetName(intId);
|
char *name = tdGetName(intId);
|
||||||
printf("%i\t%s\t", intId, name);
|
printf("%i\t%s\t", intId, name);
|
||||||
|
@ -101,13 +103,14 @@ void print_device( int index ) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void list_devices() {
|
int list_devices() {
|
||||||
|
tdInit();
|
||||||
int intNum = tdGetNumberOfDevices();
|
int intNum = tdGetNumberOfDevices();
|
||||||
if (intNum < 0) {
|
if (intNum < 0) {
|
||||||
char *errorString = tdGetErrorString(intNum);
|
char *errorString = tdGetErrorString(intNum);
|
||||||
fprintf(stderr, "Error fetching devices: %s\n", errorString);
|
fprintf(stderr, "Error fetching devices: %s\n", errorString);
|
||||||
tdReleaseString(errorString);
|
tdReleaseString(errorString);
|
||||||
return;
|
return intNum;
|
||||||
}
|
}
|
||||||
printf("Number of devices: %i\n", intNum);
|
printf("Number of devices: %i\n", intNum);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -115,9 +118,51 @@ void list_devices() {
|
||||||
print_device( i );
|
print_device( i );
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DATA_LENGTH = 20;
|
||||||
|
char protocol[DATA_LENGTH], model[DATA_LENGTH];
|
||||||
|
int sensorId = 0, dataTypes = 0;
|
||||||
|
|
||||||
|
int sensorStatus = tdSensor(protocol, DATA_LENGTH, model, DATA_LENGTH, &sensorId, &dataTypes);
|
||||||
|
if(sensorStatus == 0){
|
||||||
|
printf("\nSENSORS:\n%-20s\t%-20s\t%-5s\t%-5s\t%-8s\t%-20s\n", "PROTOCOL", "MODEL", "ID", "TEMP", "HUMIDITY", "LAST UPDATED");
|
||||||
|
}
|
||||||
|
while(sensorStatus == 0){
|
||||||
|
sensorStatus = tdSensor(protocol, DATA_LENGTH, model, DATA_LENGTH, &sensorId, &dataTypes);
|
||||||
|
|
||||||
|
char tempvalue[DATA_LENGTH];
|
||||||
|
tempvalue[0] = 0;
|
||||||
|
char humidityvalue[DATA_LENGTH];
|
||||||
|
humidityvalue[0] = 0;
|
||||||
|
char timeBuf[80];
|
||||||
|
time_t timestamp = 0;
|
||||||
|
|
||||||
|
if (dataTypes & TELLSTICK_TEMPERATURE) {
|
||||||
|
tdSensorValue(protocol, model, sensorId, TELLSTICK_TEMPERATURE, tempvalue, DATA_LENGTH, (int *)×tamp);
|
||||||
|
strcat(tempvalue, "°");
|
||||||
|
strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", localtime(×tamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataTypes & TELLSTICK_HUMIDITY) {
|
||||||
|
tdSensorValue(protocol, model, sensorId, TELLSTICK_HUMIDITY, humidityvalue, DATA_LENGTH, (int *)×tamp);
|
||||||
|
strcat(humidityvalue, "%");
|
||||||
|
strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", localtime(×tamp));
|
||||||
|
}
|
||||||
|
printf("%-20s\t%-20s\t%-5i\t%-5s\t%-8s\t%-20s\n", protocol, model, sensorId, tempvalue, humidityvalue, timeBuf);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
if(sensorStatus != TELLSTICK_ERROR_DEVICE_NOT_FOUND){
|
||||||
|
char *errorString = tdGetErrorString(sensorStatus);
|
||||||
|
fprintf(stderr, "Error fetching sensors: %s\n", errorString);
|
||||||
|
tdReleaseString(errorString);
|
||||||
|
return sensorStatus;
|
||||||
|
}
|
||||||
|
return TELLSTICK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_device( char *device ) {
|
int find_device( char *device ) {
|
||||||
|
tdInit();
|
||||||
int deviceId = atoi(device);
|
int deviceId = atoi(device);
|
||||||
if (deviceId == 0) { //Try to find the id from the name
|
if (deviceId == 0) { //Try to find the id from the name
|
||||||
int intNum = tdGetNumberOfDevices();
|
int intNum = tdGetNumberOfDevices();
|
||||||
|
@ -137,11 +182,12 @@ int find_device( char *device ) {
|
||||||
return deviceId;
|
return deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_device( bool turnOn, char *device ) {
|
int switch_device( bool turnOn, char *device ) {
|
||||||
|
tdInit();
|
||||||
int deviceId = find_device( device );
|
int deviceId = find_device( device );
|
||||||
if (deviceId == 0) {
|
if (deviceId == 0) {
|
||||||
printf("Device '%s', not found!\n", device);
|
printf("Device '%s', not found!\n", device);
|
||||||
return;
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *name = tdGetName( deviceId );
|
char *name = tdGetName( deviceId );
|
||||||
|
@ -158,17 +204,19 @@ void switch_device( bool turnOn, char *device ) {
|
||||||
|
|
||||||
printf(" - %s\n", errorString);
|
printf(" - %s\n", errorString);
|
||||||
tdReleaseString(errorString);
|
tdReleaseString(errorString);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dim_device( char *device, int level ) {
|
int dim_device( char *device, int level ) {
|
||||||
|
tdInit();
|
||||||
int deviceId = find_device( device );
|
int deviceId = find_device( device );
|
||||||
if (deviceId == 0) {
|
if (deviceId == 0) {
|
||||||
printf("Device '%s', not found!\n", device);
|
printf("Device '%s', not found!\n", device);
|
||||||
return;
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
if (level < 0 || level > 255) {
|
if (level < 0 || level > 255) {
|
||||||
printf("Level %i out of range!\n", level);
|
printf("Level %i out of range!\n", level);
|
||||||
return;
|
return TELLSTICK_ERROR_SYNTAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *name = tdGetName( deviceId );
|
char *name = tdGetName( deviceId );
|
||||||
|
@ -177,13 +225,15 @@ void dim_device( char *device, int level ) {
|
||||||
printf("Dimming device: %i %s to %i - %s\n", deviceId, name, level, errorString);
|
printf("Dimming device: %i %s to %i - %s\n", deviceId, name, level, errorString);
|
||||||
tdReleaseString(name);
|
tdReleaseString(name);
|
||||||
tdReleaseString(errorString);
|
tdReleaseString(errorString);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bell_device( char *device ) {
|
int bell_device( char *device ) {
|
||||||
|
tdInit();
|
||||||
int deviceId = find_device( device );
|
int deviceId = find_device( device );
|
||||||
if (deviceId == 0) {
|
if (deviceId == 0) {
|
||||||
printf("Device '%s', not found!\n", device);
|
printf("Device '%s', not found!\n", device);
|
||||||
return;
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *name = tdGetName( deviceId );
|
char *name = tdGetName( deviceId );
|
||||||
|
@ -192,13 +242,15 @@ void bell_device( char *device ) {
|
||||||
printf("Sending bell to: %i %s - %s\n", deviceId, name, errorString);
|
printf("Sending bell to: %i %s - %s\n", deviceId, name, errorString);
|
||||||
tdReleaseString(name);
|
tdReleaseString(name);
|
||||||
tdReleaseString(errorString);
|
tdReleaseString(errorString);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void learn_device( char *device ) {
|
int learn_device( char *device ) {
|
||||||
|
tdInit();
|
||||||
int deviceId = find_device( device );
|
int deviceId = find_device( device );
|
||||||
if (deviceId == 0) {
|
if (deviceId == 0) {
|
||||||
printf("Device '%s', not found!\n", device);
|
printf("Device '%s', not found!\n", device);
|
||||||
return;
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *name = tdGetName( deviceId );
|
char *name = tdGetName( deviceId );
|
||||||
|
@ -207,9 +259,11 @@ void learn_device( char *device ) {
|
||||||
printf("Learning device: %i %s - %s\n", deviceId, name, errorString);
|
printf("Learning device: %i %s - %s\n", deviceId, name, errorString);
|
||||||
tdReleaseString(name);
|
tdReleaseString(name);
|
||||||
tdReleaseString(errorString);
|
tdReleaseString(errorString);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_raw_command( char *command ) {
|
int send_raw_command( char *command ) {
|
||||||
|
tdInit();
|
||||||
const int MAX_LENGTH = 100;
|
const int MAX_LENGTH = 100;
|
||||||
char msg[MAX_LENGTH];
|
char msg[MAX_LENGTH];
|
||||||
|
|
||||||
|
@ -221,7 +275,7 @@ void send_raw_command( char *command ) {
|
||||||
fd = fopen(command, "r");
|
fd = fopen(command, "r");
|
||||||
if (fd == NULL) {
|
if (fd == NULL) {
|
||||||
printf("Error opening file %s\n", command);
|
printf("Error opening file %s\n", command);
|
||||||
return;
|
return TELLSTICK_ERROR_UNKNOWN;
|
||||||
}
|
}
|
||||||
fgets(msg, MAX_LENGTH, fd);
|
fgets(msg, MAX_LENGTH, fd);
|
||||||
}
|
}
|
||||||
|
@ -230,6 +284,7 @@ void send_raw_command( char *command ) {
|
||||||
char *errorString = tdGetErrorString(retval);
|
char *errorString = tdGetErrorString(retval);
|
||||||
printf("Sending raw command: %s\n", errorString);
|
printf("Sending raw command: %s\n", errorString);
|
||||||
tdReleaseString(errorString);
|
tdReleaseString(errorString);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@ -253,48 +308,56 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
print_usage( argv[0] );
|
print_usage( argv[0] );
|
||||||
return -1;
|
return -TELLSTICK_ERROR_SYNTAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( (optch = getopt_long(argc,argv,optstring,long_opts,&longindex)) != -1 )
|
int returnSuccess = 0;
|
||||||
|
while ( (optch = getopt_long(argc,argv,optstring,long_opts,&longindex)) != -1 ){
|
||||||
|
int success = 0;
|
||||||
switch (optch) {
|
switch (optch) {
|
||||||
case 'b' :
|
case 'b' :
|
||||||
bell_device( &optarg[0] );
|
success = bell_device( &optarg[0] );
|
||||||
break;
|
break;
|
||||||
case 'd' :
|
case 'd' :
|
||||||
if (level >= 0) {
|
if (level >= 0) {
|
||||||
dim_device( &optarg[0], level );
|
success = dim_device( &optarg[0], level );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
printf("Dim level missing or incorrect value.\n");
|
||||||
|
success = TELLSTICK_ERROR_SYNTAX;
|
||||||
break;
|
break;
|
||||||
case 'f' :
|
case 'f' :
|
||||||
switch_device(false, &optarg[0]);
|
success = switch_device(false, &optarg[0]);
|
||||||
break;
|
break;
|
||||||
case 'h' :
|
case 'h' :
|
||||||
print_usage( argv[0] );
|
print_usage( argv[0] );
|
||||||
break;
|
success = TELLSTICK_SUCCESS;
|
||||||
case 'i' :
|
case 'i' :
|
||||||
print_version( );
|
print_version( );
|
||||||
break;
|
success = TELLSTICK_SUCCESS;
|
||||||
case 'l' :
|
case 'l' :
|
||||||
list_devices();
|
success = list_devices();
|
||||||
break;
|
break;
|
||||||
case 'n' :
|
case 'n' :
|
||||||
switch_device(true, &optarg[0]);
|
success = switch_device(true, &optarg[0]);
|
||||||
break;
|
break;
|
||||||
case 'e' :
|
case 'e' :
|
||||||
learn_device(&optarg[0]);
|
success = learn_device(&optarg[0]);
|
||||||
break;
|
break;
|
||||||
case 'r' :
|
case 'r' :
|
||||||
send_raw_command(&optarg[0]);
|
success = send_raw_command(&optarg[0]);
|
||||||
break;
|
break;
|
||||||
case 'v' :
|
case 'v' :
|
||||||
level = atoi( &optarg[0] );
|
level = atoi( &optarg[0] );
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
print_usage( argv[0] );
|
print_usage( argv[0] );
|
||||||
return -1;
|
success = TELLSTICK_ERROR_SYNTAX;
|
||||||
}
|
}
|
||||||
|
if(success != TELLSTICK_SUCCESS){
|
||||||
|
returnSuccess = success; //return last error message
|
||||||
|
}
|
||||||
|
}
|
||||||
tdClose(); //Cleaning up
|
tdClose(); //Cleaning up
|
||||||
return 0;
|
return -returnSuccess;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,11 @@ LiveMessageToken::LiveMessageToken(const QString &value) {
|
||||||
stringVal = value;
|
stringVal = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LiveMessageToken::LiveMessageToken(int value) {
|
||||||
|
valueType = Int;
|
||||||
|
intVal = value;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray LiveMessageToken::toByteArray() const {
|
QByteArray LiveMessageToken::toByteArray() const {
|
||||||
if (valueType == Int) {
|
if (valueType == Int) {
|
||||||
return QString("i%1s").arg(intVal, 0, 16).toUtf8();
|
return QString("i%1s").arg(intVal, 0, 16).toUtf8();
|
||||||
|
@ -122,7 +127,7 @@ void LiveMessageTokenScriptWrapper::add(LiveMessageTokenScriptWrapper *t) {
|
||||||
p_token.listVal << t->p_token;
|
p_token.listVal << t->p_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LiveMessageTokenScriptWrapper::getInt(const QString &key, int defaultValue) {
|
int LiveMessageTokenScriptWrapper::getInt(const QString &key, int defaultValue) const {
|
||||||
if (p_token.valueType != LiveMessageToken::Dictionary) {
|
if (p_token.valueType != LiveMessageToken::Dictionary) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
@ -132,6 +137,16 @@ int LiveMessageTokenScriptWrapper::getInt(const QString &key, int defaultValue)
|
||||||
return p_token.dictVal[key].intVal;
|
return p_token.dictVal[key].intVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString LiveMessageTokenScriptWrapper::getString(const QString &key, const QString &defaultValue) const {
|
||||||
|
if (p_token.valueType != LiveMessageToken::Dictionary) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
if (!p_token.dictVal.contains(key)) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return p_token.dictVal[key].stringVal;
|
||||||
|
}
|
||||||
|
|
||||||
int LiveMessageTokenScriptWrapper::intVal() const {
|
int LiveMessageTokenScriptWrapper::intVal() const {
|
||||||
return p_token.intVal;
|
return p_token.intVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ public:
|
||||||
|
|
||||||
LiveMessageToken();
|
LiveMessageToken();
|
||||||
LiveMessageToken(const QString &value);
|
LiveMessageToken(const QString &value);
|
||||||
|
LiveMessageToken(int value);
|
||||||
QByteArray toByteArray() const;
|
QByteArray toByteArray() const;
|
||||||
static LiveMessageToken parseToken(const QByteArray &string, int* start);
|
static LiveMessageToken parseToken(const QByteArray &string, int* start);
|
||||||
|
|
||||||
|
@ -34,13 +35,14 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void add(LiveMessageTokenScriptWrapper *token);
|
void add(LiveMessageTokenScriptWrapper *token);
|
||||||
|
|
||||||
int getInt(const QString &key, int defaultValue = 0);
|
int getInt(const QString &key, int defaultValue = 0) const;
|
||||||
|
QString getString(const QString &key, const QString &defaultValue = "") const;
|
||||||
|
|
||||||
int intVal() const;
|
int intVal() const;
|
||||||
|
|
||||||
void set(const QString &key, int value);
|
void set(const QString &key, int value);
|
||||||
void set(const QString &key, const QString &value);
|
void set(const QString &key, const QString &value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LiveMessageToken p_token;
|
LiveMessageToken p_token;
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ public:
|
||||||
class Server;
|
class Server;
|
||||||
|
|
||||||
QSslSocket *socket;
|
QSslSocket *socket;
|
||||||
QTimer timer;
|
QTimer pingTimer, pongTimer;
|
||||||
bool registered;
|
bool registered;
|
||||||
QUrl registerUrl;
|
QUrl registerUrl;
|
||||||
QString uuid, hashMethod;
|
QString uuid, hashMethod;
|
||||||
|
@ -46,8 +46,11 @@ LiveObject::LiveObject( QScriptEngine *engine, QObject * parent )
|
||||||
connect(d->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(stateChanged(QAbstractSocket::SocketState)));
|
connect(d->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(stateChanged(QAbstractSocket::SocketState)));
|
||||||
connect(d->socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
|
connect(d->socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
|
||||||
|
|
||||||
d->timer.setInterval(60000); //Once a minute
|
d->pingTimer.setInterval(120000); //Two minutes
|
||||||
connect(&d->timer, SIGNAL(timeout()), this, SLOT(pingServer()));
|
d->pongTimer.setInterval(360000); //Six minutes
|
||||||
|
d->pongTimer.setSingleShot(true);
|
||||||
|
connect(&d->pingTimer, SIGNAL(timeout()), this, SLOT(pingServer()));
|
||||||
|
connect(&d->pongTimer, SIGNAL(timeout()), this, SLOT(pongTimeout()));
|
||||||
|
|
||||||
d->manager = new QNetworkAccessManager(this);
|
d->manager = new QNetworkAccessManager(this);
|
||||||
connect(d->manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(serverAssignReply(QNetworkReply*)));
|
connect(d->manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(serverAssignReply(QNetworkReply*)));
|
||||||
|
@ -102,6 +105,8 @@ void LiveObject::readyRead() {
|
||||||
//qDebug() << "HASH mismatch!" << msg->name();
|
//qDebug() << "HASH mismatch!" << msg->name();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
d->pongTimer.stop();
|
||||||
|
d->pongTimer.start();
|
||||||
|
|
||||||
if (msg->name() == "") {
|
if (msg->name() == "") {
|
||||||
return;
|
return;
|
||||||
|
@ -122,6 +127,14 @@ void LiveObject::readyRead() {
|
||||||
s.setValue("Live/UUID", d->uuid);
|
s.setValue("Live/UUID", d->uuid);
|
||||||
emit notRegistered();
|
emit notRegistered();
|
||||||
emit errorChanged("Not registered");
|
emit errorChanged("Not registered");
|
||||||
|
} else if (msg->name() == "command") {
|
||||||
|
if (msg->arg(0).valueType == LiveMessageToken::Dictionary && msg->arg(0).dictVal.contains("ACK")) {
|
||||||
|
int ack = msg->arg(0).dictVal["ACK"].intVal;
|
||||||
|
LiveMessage msg("ACK");
|
||||||
|
msg.append(ack);
|
||||||
|
this->sendMessage(msg);
|
||||||
|
}
|
||||||
|
emit messageReceived(msg.data());
|
||||||
} else {
|
} else {
|
||||||
emit messageReceived(msg.data());
|
emit messageReceived(msg.data());
|
||||||
}
|
}
|
||||||
|
@ -132,7 +145,7 @@ void LiveObject::refreshServerList() {
|
||||||
emit statusChanged("Discover servers");
|
emit statusChanged("Discover servers");
|
||||||
d->serverList.clear();
|
d->serverList.clear();
|
||||||
QUrl url(TELLDUS_LIVE_URI);
|
QUrl url(TELLDUS_LIVE_URI);
|
||||||
QPair<QString, QString> version("protocolVersion", "1");
|
QPair<QString, QString> version("protocolVersion", "2");
|
||||||
QList<QPair<QString, QString> > query;
|
QList<QPair<QString, QString> > query;
|
||||||
query.append(version);
|
query.append(version);
|
||||||
url.setQueryItems(query);
|
url.setQueryItems(query);
|
||||||
|
@ -156,6 +169,8 @@ void LiveObject::sendMessage(const LiveMessage &message) {
|
||||||
|
|
||||||
d->socket->write(msg.toByteArray());
|
d->socket->write(msg.toByteArray());
|
||||||
d->socket->flush();
|
d->socket->flush();
|
||||||
|
d->pingTimer.stop();
|
||||||
|
d->pingTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LiveObject::sendMessage(LiveMessage *message) {
|
void LiveObject::sendMessage(LiveMessage *message) {
|
||||||
|
@ -170,7 +185,8 @@ void LiveObject::p_connected() {
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
d->uuid = settings.value("Live/UUID", "").toString();
|
d->uuid = settings.value("Live/UUID", "").toString();
|
||||||
|
|
||||||
d->timer.start(); //For pings
|
d->pingTimer.start(); //For pings
|
||||||
|
d->pongTimer.start(); //For pongs
|
||||||
LiveMessage msg("Register");
|
LiveMessage msg("Register");
|
||||||
|
|
||||||
LiveMessageToken token;
|
LiveMessageToken token;
|
||||||
|
@ -188,7 +204,12 @@ void LiveObject::p_connected() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LiveObject::p_disconnected() {
|
void LiveObject::p_disconnected() {
|
||||||
d->timer.stop();
|
d->pingTimer.stop();
|
||||||
|
d->pongTimer.stop();
|
||||||
|
if (d->registered) {
|
||||||
|
//Clear the registered status
|
||||||
|
emit errorChanged("Disconnected from server");
|
||||||
|
}
|
||||||
d->registered = false;
|
d->registered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,11 +219,12 @@ void LiveObject::error( QAbstractSocket::SocketError socketError ) {
|
||||||
|
|
||||||
void LiveObject::stateChanged( QAbstractSocket::SocketState socketState ) {
|
void LiveObject::stateChanged( QAbstractSocket::SocketState socketState ) {
|
||||||
if (socketState == QAbstractSocket::UnconnectedState) {
|
if (socketState == QAbstractSocket::UnconnectedState) {
|
||||||
int timeout = rand() % 20 + 10; //Random timeout from 10-30s to avoid flooding the servers
|
int timeout = rand() % 40 + 10; //Random timeout from 10-50s to avoid flooding the servers
|
||||||
QTimer::singleShot(timeout*1000, this, SLOT(connectToServer()));
|
QTimer::singleShot(timeout*1000, this, SLOT(connectToServer()));
|
||||||
emit statusChanged("Reconnecting in " + QString::number(timeout) + " seconds...");
|
emit statusChanged("Reconnecting in " + QString::number(timeout) + " seconds...");
|
||||||
} else if (socketState == QAbstractSocket::ConnectingState) {
|
} else if (socketState == QAbstractSocket::ConnectingState) {
|
||||||
emit statusChanged("Connecting...");
|
emit statusChanged("Connecting...");
|
||||||
|
emit errorChanged("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,8 +250,10 @@ void LiveObject::sslErrors( const QList<QSslError> & errors ) {
|
||||||
void LiveObject::serverAssignReply( QNetworkReply *r ) {
|
void LiveObject::serverAssignReply( QNetworkReply *r ) {
|
||||||
r->deleteLater();
|
r->deleteLater();
|
||||||
if (r->error() != QNetworkReply::NoError) {
|
if (r->error() != QNetworkReply::NoError) {
|
||||||
|
int timeout = rand() % 300 + 60; //Random timeout from 60s-6min to avoid flooding the servers
|
||||||
emit errorChanged(r->errorString());
|
emit errorChanged(r->errorString());
|
||||||
emit statusChanged("Error retrieving server list");
|
emit statusChanged("Retrying in " + QString::number(timeout) + " seconds...");
|
||||||
|
QTimer::singleShot(timeout * 1000, this, SLOT(connectToServer()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QXmlStreamReader xml(r);
|
QXmlStreamReader xml(r);
|
||||||
|
@ -253,7 +277,7 @@ void LiveObject::serverAssignReply( QNetworkReply *r ) {
|
||||||
d->serverRefreshTime = QDateTime::currentDateTime();
|
d->serverRefreshTime = QDateTime::currentDateTime();
|
||||||
QTimer::singleShot(0, this, SLOT(connectToServer()));
|
QTimer::singleShot(0, this, SLOT(connectToServer()));
|
||||||
} else {
|
} else {
|
||||||
int timeout = rand() % 20 + 10; //Random timeout from 10-30s to avoid flooding the servers
|
int timeout = rand() % 300 + 60; //Random timeout from 60-6min to avoid flooding the servers
|
||||||
emit errorChanged("No servers found");
|
emit errorChanged("No servers found");
|
||||||
emit statusChanged("Retrying in " + QString::number(timeout) + " seconds...");
|
emit statusChanged("Retrying in " + QString::number(timeout) + " seconds...");
|
||||||
QTimer::singleShot(timeout * 1000, this, SLOT(connectToServer()));
|
QTimer::singleShot(timeout * 1000, this, SLOT(connectToServer()));
|
||||||
|
@ -270,7 +294,7 @@ QByteArray LiveObject::signatureForMessage( const QByteArray &message ) {
|
||||||
LiveMessageToken LiveObject::generateVersionToken() {
|
LiveMessageToken LiveObject::generateVersionToken() {
|
||||||
LiveMessageToken token;
|
LiveMessageToken token;
|
||||||
token.valueType = LiveMessageToken::Dictionary;
|
token.valueType = LiveMessageToken::Dictionary;
|
||||||
token.dictVal["protocol"] = LiveMessageToken("1");
|
token.dictVal["protocol"] = LiveMessageToken(2);
|
||||||
token.dictVal["version"] = LiveMessageToken(TELLDUS_CENTER_VERSION);
|
token.dictVal["version"] = LiveMessageToken(TELLDUS_CENTER_VERSION);
|
||||||
#if defined(Q_WS_WIN)
|
#if defined(Q_WS_WIN)
|
||||||
token.dictVal["os"] = LiveMessageToken("windows");
|
token.dictVal["os"] = LiveMessageToken("windows");
|
||||||
|
@ -314,3 +338,7 @@ LiveMessageToken LiveObject::generateVersionToken() {
|
||||||
#endif
|
#endif
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LiveObject::pongTimeout() {
|
||||||
|
this->disconnect();
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ private slots:
|
||||||
void p_connected();
|
void p_connected();
|
||||||
void p_disconnected();
|
void p_disconnected();
|
||||||
void readyRead();
|
void readyRead();
|
||||||
|
void pongTimeout();
|
||||||
void error( QAbstractSocket::SocketError socketError );
|
void error( QAbstractSocket::SocketError socketError );
|
||||||
void stateChanged( QAbstractSocket::SocketState socketState );
|
void stateChanged( QAbstractSocket::SocketState socketState );
|
||||||
void sslErrors( const QList<QSslError> & errors );
|
void sslErrors( const QList<QSslError> & errors );
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue