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/
|
||||
qtcreator-build/
|
||||
Doxyfile
|
||||
html/
|
||||
latex/
|
||||
CMakeLists.txt.user
|
||||
|
|
|
@ -187,10 +187,54 @@
|
|||
* tdReleaseString(name);
|
||||
* \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
|
||||
*
|
||||
* To get events from either a TellStick Duo or if another software changes the
|
||||
* status of a device you have to register for a callback.
|
||||
* To get events from either a TellStick Duo, another software changes the
|
||||
* status of a device, or new sensors values you have to register for a callback.
|
||||
*
|
||||
* \subsection sec_events_registering Registering for callbacks
|
||||
*
|
||||
|
@ -198,6 +242,7 @@
|
|||
* \li tdRegisterDeviceEvent()
|
||||
* \li tdRegisterDeviceChangeEvent()
|
||||
* \li tdRegisterRawDeviceEvent()
|
||||
* \li tdRegisterSensorEvent()
|
||||
*
|
||||
* 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
|
||||
|
@ -212,13 +257,14 @@
|
|||
*
|
||||
* Many devices (for example motion detectors) resends their messages many times
|
||||
* to ensure that they are received correctly. If a deviceeventcallback or
|
||||
* rawdeviceeventcallback in turn is calling a controlling function, for example tdTurnOn,
|
||||
* it may be neccessary to implement some solution to wait for the device to finish its
|
||||
* resending, before executing the controlling function. See how this can be done in the python example.
|
||||
* rawdeviceeventcallback in turn is calling a controlling function, for example
|
||||
* tdTurnOn, it may be neccessary to implement some solution to wait for the
|
||||
* 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
|
||||
*
|
||||
* telldus-core currently implements three different callback function for
|
||||
* telldus-core currently implements four different callback function for
|
||||
* different purposes.
|
||||
*
|
||||
* \subsubsection sec_events_callbacks_deviceevent DeviceEvent
|
||||
|
@ -234,9 +280,10 @@
|
|||
* - const char *data - For some methods this contains data. For TELLSTICK_DIM
|
||||
* this hold the current value.
|
||||
* - 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
|
||||
*
|
||||
* 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
|
||||
* in sync.
|
||||
|
@ -256,19 +303,33 @@
|
|||
* - TELLSTICK_CHANGE_PROTOCOL - Use tdGetProtocol() to read the new value.
|
||||
* - TELLSTICK_CHANGE_MODEL - Use tdGetModel() to read the new value.
|
||||
* - 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
|
||||
*
|
||||
* Use this callback with caution. It outputs everything from the Duo without
|
||||
* any preprocessing. This can be used to get events from devices not already
|
||||
* configured.
|
||||
* Use this callback with caution. It outputs everything from a TellStick Duo
|
||||
* without any preprocessing. This can be used to get events from devices not
|
||||
* already configured.
|
||||
*
|
||||
* Parameters:
|
||||
* - const char *data - raw device data
|
||||
* - int controllerId - id of receiving controller, can identify the TellStick if several exists in the system
|
||||
* - 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
|
||||
*
|
||||
|
|
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 "common.h"
|
||||
|
||||
using namespace TelldusCore;
|
||||
|
||||
|
@ -28,7 +29,9 @@ bool TDDeviceEventDispatcher::done() const {
|
|||
}
|
||||
|
||||
void TDDeviceEventDispatcher::run() {
|
||||
char *str = wrapStdString(strData);
|
||||
d->event(deviceId, method, strData.c_str(), d->id, d->context);
|
||||
|
||||
doneRunning = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -114,6 +114,9 @@ bool Client::getBoolFromService(const Message &msg) {
|
|||
|
||||
int Client::getIntegerFromService(const Message &msg) {
|
||||
std::wstring response = sendToService(msg);
|
||||
if (response.compare(L"") == 0) {
|
||||
return TELLSTICK_ERROR_COMMUNICATING_SERVICE;
|
||||
}
|
||||
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""){
|
||||
//a message arrived
|
||||
std::wstring type = Message::takeString(&clientMessage);
|
||||
|
@ -282,16 +286,46 @@ void Client::cleanupCallbacks() {
|
|||
}
|
||||
|
||||
std::wstring Client::sendToService(const Message &msg) {
|
||||
Socket s;
|
||||
s.connect(L"TelldusClient");
|
||||
if (!s.isConnected()) { //Connection failed
|
||||
TelldusCore::Message msg;
|
||||
msg.addArgument(TELLSTICK_ERROR_CONNECTING_SERVICE);
|
||||
return msg;
|
||||
|
||||
int tries = 0;
|
||||
std::wstring readData;
|
||||
while(tries < 20){
|
||||
tries++;
|
||||
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(){
|
||||
|
|
|
@ -57,6 +57,9 @@ using namespace TelldusCore;
|
|||
* @def TELLSTICK_SUCCESS
|
||||
* Error code. Returned when the command succeeded.
|
||||
*
|
||||
* @def TELLSTICK_ERROR_BROKEN_PIPE
|
||||
* Error code. Pipe broken during communication.
|
||||
*
|
||||
* @def TELLSTICK_ERROR_NOT_FOUND
|
||||
* 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
|
||||
* 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
|
||||
* 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_DEVICE_NOT_FOUND
|
||||
* @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
|
||||
*/
|
||||
char * WINAPI tdGetErrorString(int intErrorNo) {
|
||||
const int numResponses = 8;
|
||||
const int numResponses = 10;
|
||||
const char *responses[numResponses] = {
|
||||
"Success",
|
||||
"TellStick not found",
|
||||
|
@ -491,7 +507,10 @@ char * WINAPI tdGetErrorString(int intErrorNo) {
|
|||
"The method you tried to use is not supported by the device",
|
||||
"An error occurred while communicating with TellStick",
|
||||
"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;
|
||||
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
|
||||
*/
|
||||
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");
|
||||
msg.addArgument(command);
|
||||
msg.addArgument(wcommand);
|
||||
msg.addArgument(reserved);
|
||||
return Client::getIntegerFromService(msg);
|
||||
}
|
||||
|
@ -534,11 +557,36 @@ void WINAPI tdDisconnectTellStickController(int vid, int pid, const char *serial
|
|||
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) {
|
||||
Client *client = Client::getInstance();
|
||||
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) {
|
||||
Message msg(L"tdSensorValue");
|
||||
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_CONNECTING_SERVICE -6
|
||||
#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
|
||||
|
||||
//Device typedef
|
||||
|
|
|
@ -23,21 +23,70 @@ Message::~Message(void) {
|
|||
}
|
||||
|
||||
void Message::addArgument(const std::wstring &value) {
|
||||
std::wstringstream st;
|
||||
st << (int)value.size();
|
||||
this->append(st.str());
|
||||
//std::wstringstream st;
|
||||
//st << (int)value.size();
|
||||
this->append(TelldusCore::intToWstring(value.size())); //st.str());
|
||||
this->append(L":");
|
||||
this->append(value);
|
||||
}
|
||||
|
||||
void Message::addArgument(int value) {
|
||||
std::wstringstream st;
|
||||
st << (int)value;
|
||||
//std::wstringstream st;
|
||||
//st << (int)value;
|
||||
this->append(L"i");
|
||||
this->append(st.str());
|
||||
this->append(TelldusCore::intToWstring(value)); // st.str());
|
||||
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) {
|
||||
this->addArgument(TelldusCore::charToWstring(value));
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ namespace TelldusCore {
|
|||
~Message(void);
|
||||
|
||||
void addArgument(const std::wstring &);
|
||||
//void addSpecialArgument(const std::wstring &);
|
||||
//void addSpecialArgument(int);
|
||||
//void addSpecialArgument(const char *);
|
||||
void addArgument(int);
|
||||
void addArgument(const char *);
|
||||
|
||||
|
|
|
@ -78,9 +78,9 @@ std::wstring Socket::read() {
|
|||
std::wstring Socket::read(int timeout) {
|
||||
struct timeval tv;
|
||||
char inbuf[BUFSIZE];
|
||||
memset(inbuf, '\0', sizeof(inbuf));
|
||||
|
||||
FD_SET(d->socket, &d->infds);
|
||||
std::string msg;
|
||||
while(isConnected()) {
|
||||
tv.tv_sec = floor(timeout / 1000.0);
|
||||
tv.tv_usec = timeout % 1000;
|
||||
|
@ -93,21 +93,28 @@ std::wstring Socket::read(int timeout) {
|
|||
continue;
|
||||
}
|
||||
|
||||
int received = recv(d->socket, inbuf, BUFSIZE - 1, 0);
|
||||
if (received <= 0) {
|
||||
int received = BUFSIZE;
|
||||
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);
|
||||
d->connected = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
std::string msg(inbuf);
|
||||
return TelldusCore::charToWstring(msg.c_str());
|
||||
}
|
||||
|
||||
void Socket::stopReadWait(){
|
||||
TelldusCore::MutexLocker locker(&d->mutex);
|
||||
d->connected = false;
|
||||
//TODO somehow signal the socket here?
|
||||
}
|
||||
|
||||
void Socket::write(const std::wstring &msg) {
|
||||
|
|
|
@ -37,6 +37,7 @@ Socket::~Socket(void){
|
|||
SetEvent(d->readEvent); //signal for break
|
||||
if (d->hPipe != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(d->hPipe);
|
||||
d->hPipe = 0;
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
@ -89,39 +90,52 @@ std::wstring Socket::read(int timeout){
|
|||
|
||||
memset(&oOverlap, 0, sizeof(OVERLAPPED));
|
||||
|
||||
d->readEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
||||
d->readEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
oOverlap.hEvent = d->readEvent;
|
||||
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);
|
||||
|
||||
result = WaitForSingleObject(oOverlap.hEvent, timeout);
|
||||
|
||||
if(!d->running){
|
||||
CancelIo(d->hPipe);
|
||||
CloseHandle(d->readEvent);
|
||||
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;
|
||||
ReadFile( d->hPipe, &buf, sizeof(buf)-sizeof(wchar_t), &cbBytesRead, &oOverlap);
|
||||
|
||||
result = WaitForSingleObject(oOverlap.hEvent, timeout);
|
||||
|
||||
if(!d->running){
|
||||
CancelIo(d->hPipe);
|
||||
WaitForSingleObject(oOverlap.hEvent, INFINITE);
|
||||
d->readEvent = 0;
|
||||
CloseHandle(oOverlap.hEvent);
|
||||
return L"";
|
||||
}
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
CancelIo(d->hPipe);
|
||||
CloseHandle(d->readEvent);
|
||||
return buf;
|
||||
if (result == WAIT_TIMEOUT) {
|
||||
CancelIo(d->hPipe);
|
||||
// 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){
|
||||
|
@ -129,26 +143,33 @@ void Socket::write(const std::wstring &msg){
|
|||
OVERLAPPED oOverlap;
|
||||
DWORD bytesWritten = 0;
|
||||
int result;
|
||||
BOOL fSuccess;
|
||||
BOOL fSuccess = false;
|
||||
|
||||
memset(&oOverlap, 0, sizeof(OVERLAPPED));
|
||||
|
||||
HANDLE writeEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
||||
HANDLE writeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
oOverlap.hEvent = writeEvent;
|
||||
|
||||
WriteFile(d->hPipe, msg.data(), (DWORD)msg.length()*sizeof(wchar_t), &bytesWritten, &oOverlap);
|
||||
|
||||
result = WaitForSingleObject(writeEvent, 500);
|
||||
if (result == WAIT_TIMEOUT) {
|
||||
CancelIo(d->hPipe);
|
||||
CloseHandle(writeEvent);
|
||||
d->connected = false;
|
||||
return;
|
||||
BOOL writeSuccess = WriteFile(d->hPipe, msg.data(), (DWORD)msg.length()*sizeof(wchar_t), &bytesWritten, &oOverlap);
|
||||
result = GetLastError();
|
||||
if (writeSuccess || result == ERROR_IO_PENDING) {
|
||||
result = WaitForSingleObject(writeEvent, 500);
|
||||
if (result == WAIT_TIMEOUT) {
|
||||
CancelIo(d->hPipe);
|
||||
WaitForSingleObject(oOverlap.hEvent, INFINITE);
|
||||
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);
|
||||
if (!fSuccess) {
|
||||
CancelIo(d->hPipe);
|
||||
CloseHandle(d->hPipe);
|
||||
d->hPipe = 0;
|
||||
d->connected = false;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <windows.h>
|
||||
|
@ -91,17 +92,58 @@ bool TelldusCore::comparei(std::wstring stringA, std::wstring stringB) {
|
|||
}
|
||||
|
||||
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;
|
||||
st << value;
|
||||
return st.str();
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
st << value;
|
||||
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){
|
||||
std::wstringstream inputstream;
|
||||
inputstream << input;
|
||||
|
@ -158,3 +200,48 @@ std::string TelldusCore::wideToString(const std::wstring &input) {
|
|||
return retval;
|
||||
#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
|
||||
|
||||
#include <string>
|
||||
#include <stdarg.h>
|
||||
|
||||
namespace TelldusCore {
|
||||
std::wstring charToWstring(const char *value);
|
||||
|
@ -10,10 +11,14 @@ namespace TelldusCore {
|
|||
|
||||
bool comparei(std::wstring stringA, std::wstring stringB);
|
||||
std::wstring intToWstring(int value);
|
||||
//std::wstring intToWStringSafe(int value);
|
||||
std::string intToString(int value);
|
||||
std::string wideToString(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
|
||||
|
|
|
@ -19,10 +19,12 @@ SET( telldus-service_SRCS
|
|||
Device.cpp
|
||||
DeviceManager.cpp
|
||||
Event.cpp
|
||||
Log.cpp
|
||||
Sensor.cpp
|
||||
Settings.cpp
|
||||
TelldusMain.cpp
|
||||
TellStick.cpp
|
||||
Timer.cpp
|
||||
EventUpdateManager.cpp
|
||||
)
|
||||
SET( telldus-service_protocol_SRCS
|
||||
|
@ -34,6 +36,8 @@ SET( telldus-service_protocol_SRCS
|
|||
ProtocolComen.cpp
|
||||
ProtocolEverflourish.h
|
||||
ProtocolEverflourish.cpp
|
||||
ProtocolFineoffset.h
|
||||
ProtocolFineoffset.cpp
|
||||
ProtocolFuhaote.h
|
||||
ProtocolFuhaote.cpp
|
||||
ProtocolGroup.h
|
||||
|
@ -42,8 +46,12 @@ SET( telldus-service_protocol_SRCS
|
|||
ProtocolHasta.cpp
|
||||
ProtocolIkea.h
|
||||
ProtocolIkea.cpp
|
||||
ProtocolMandolyn.h
|
||||
ProtocolMandolyn.cpp
|
||||
ProtocolNexa.h
|
||||
ProtocolNexa.cpp
|
||||
ProtocolOregon.h
|
||||
ProtocolOregon.cpp
|
||||
ProtocolRisingSun.h
|
||||
ProtocolRisingSun.cpp
|
||||
ProtocolSartano.h
|
||||
|
@ -72,11 +80,13 @@ SET( telldus-service_HDRS
|
|||
DeviceManager.h
|
||||
Event.h
|
||||
EventHandler.h
|
||||
EventUpdateManager.h
|
||||
Log.h
|
||||
Sensor.h
|
||||
Settings.h
|
||||
TelldusMain.h
|
||||
TellStick.h
|
||||
EventUpdateManager.h
|
||||
Timer.h
|
||||
)
|
||||
FIND_PACKAGE(Threads REQUIRED)
|
||||
LIST(APPEND telldus-service_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
@ -129,15 +139,27 @@ ELSEIF (WIN32) #### Windows ####
|
|||
main_win.cpp
|
||||
SettingsWinRegistry.cpp
|
||||
TelldusWinService_win.cpp
|
||||
Messages.mc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Messages.rc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Messages.h
|
||||
)
|
||||
LIST(APPEND telldus-service_HDRS
|
||||
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 ####
|
||||
SET(DEFAULT_FTDI_ENGINE "libftdi")
|
||||
FIND_LIBRARY(CONFUSE_LIBRARY confuse)
|
||||
ADD_DEFINITIONS( -D_CONFUSE )
|
||||
ADD_DEFINITIONS( -D_LINUX )
|
||||
|
||||
SET( telldus-service_TARGET telldusd )
|
||||
LIST(APPEND telldus-service_SRCS
|
||||
|
|
|
@ -76,6 +76,7 @@ void ClientCommunicationHandler::parseMessage(const std::wstring &clientMessage,
|
|||
if (function == L"tdTurnOn") {
|
||||
int deviceId = TelldusCore::Message::takeInt(&msg);
|
||||
(*intReturn) = d->deviceManager->doAction(deviceId, TELLSTICK_TURNON, 0);
|
||||
|
||||
} else if (function == L"tdTurnOff") {
|
||||
int deviceId = TelldusCore::Message::takeInt(&msg);
|
||||
(*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);
|
||||
int reserved = TelldusCore::Message::takeInt(&msg);
|
||||
(*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") {
|
||||
int vid = TelldusCore::Message::takeInt(&msg);
|
||||
|
|
|
@ -91,46 +91,57 @@ void ConnectionListener::run() {
|
|||
|
||||
d->hEvent = CreateEvent(NULL, true, false, NULL);
|
||||
oOverlap.hEvent = d->hEvent;
|
||||
bool recreate = true;
|
||||
|
||||
while (1) {
|
||||
hPipe = CreateNamedPipe(
|
||||
(const wchar_t *)d->pipename.c_str(), // pipe name
|
||||
PIPE_ACCESS_DUPLEX | // read/write access
|
||||
FILE_FLAG_OVERLAPPED, //Overlapped mode
|
||||
PIPE_TYPE_MESSAGE | // message type pipe
|
||||
PIPE_READMODE_MESSAGE | // message-read mode
|
||||
PIPE_WAIT, // blocking mode
|
||||
PIPE_UNLIMITED_INSTANCES, // max. instances
|
||||
BUFSIZE, // output buffer size
|
||||
BUFSIZE, // input buffer size
|
||||
0, // client time-out
|
||||
&d->sa); // default security attribute
|
||||
BOOL alreadyConnected = false;
|
||||
if (recreate) {
|
||||
hPipe = CreateNamedPipe(
|
||||
(const wchar_t *)d->pipename.c_str(), // pipe name
|
||||
PIPE_ACCESS_DUPLEX | // read/write access
|
||||
FILE_FLAG_OVERLAPPED, //Overlapped mode
|
||||
PIPE_TYPE_MESSAGE | // message type pipe
|
||||
PIPE_READMODE_MESSAGE | // message-read mode
|
||||
PIPE_WAIT, // blocking mode
|
||||
PIPE_UNLIMITED_INSTANCES, // max. instances
|
||||
BUFSIZE, // output buffer size
|
||||
BUFSIZE, // input buffer size
|
||||
0, // client time-out
|
||||
&d->sa); // default security attribute
|
||||
|
||||
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||
//TelldusCore::logMessage("Could not create named pipe");
|
||||
return;
|
||||
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||
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);
|
||||
|
||||
DWORD result = WaitForSingleObject(oOverlap.hEvent, 1000);
|
||||
|
||||
if (!d->running) {
|
||||
break;
|
||||
}
|
||||
if(result == WAIT_TIMEOUT){
|
||||
CloseHandle(hPipe);
|
||||
continue;
|
||||
}
|
||||
BOOL connected = GetOverlappedResult(hPipe, &oOverlap, &cbBytesRead, false);
|
||||
|
||||
if (!connected) {
|
||||
CloseHandle(hPipe);
|
||||
return;
|
||||
if (!connected) {
|
||||
CloseHandle(hPipe);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ConnectionListenerEventData *data = new ConnectionListenerEventData();
|
||||
ResetEvent(oOverlap.hEvent);
|
||||
data->socket = new TelldusCore::Socket(hPipe);
|
||||
d->waitEvent->signal(data);
|
||||
|
||||
recreate = true;
|
||||
}
|
||||
|
||||
CloseHandle(d->hEvent);
|
||||
|
|
|
@ -16,6 +16,7 @@ public:
|
|||
|
||||
virtual int firmwareVersion() = 0;
|
||||
virtual int send( const std::string &message ) = 0;
|
||||
virtual int reset() = 0;
|
||||
|
||||
protected:
|
||||
Controller(int id, Event *event);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include "Controller.h"
|
||||
#include "Mutex.h"
|
||||
#include "TellStick.h"
|
||||
#include "Log.h"
|
||||
#include "../client/telldus-core.h"
|
||||
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
|
@ -119,3 +121,47 @@ void ControllerManager::loadControllers() {
|
|||
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);
|
||||
|
||||
Controller *getBestControllerById(int id);
|
||||
|
||||
protected:
|
||||
void loadControllers();
|
||||
void queryControllerStatus();
|
||||
int resetController(Controller *controller);
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "Settings.h"
|
||||
#include "Strings.h"
|
||||
#include "Message.h"
|
||||
#include "common.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
@ -432,9 +432,31 @@ int DeviceManager::doAction(int deviceId, int action, unsigned char data){
|
|||
}
|
||||
else{
|
||||
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){
|
||||
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 {
|
||||
Log::error("No contoller (TellStick) found after one retry. Giving up.");
|
||||
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);
|
||||
}
|
||||
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{
|
||||
//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){
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,15 +51,17 @@ void EventHandler::signal(Event *) {
|
|||
}
|
||||
|
||||
bool EventHandler::waitForAny() {
|
||||
int result = WaitForMultipleObjects(d->eventCount, d->eventArray, FALSE, INFINITE);
|
||||
|
||||
TelldusCore::MutexLocker locker(&d->mutex);
|
||||
if (result == WAIT_TIMEOUT) {
|
||||
return false;
|
||||
|
||||
while(1){
|
||||
int result = WaitForMultipleObjects(d->eventCount, d->eventArray, FALSE, 1000);
|
||||
if (result == WAIT_TIMEOUT) {
|
||||
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){
|
||||
|
||||
int connected = 0;
|
||||
for(SocketList::iterator it = d->clients.begin(); it != d->clients.end();){
|
||||
|
||||
if((*it)->isConnected()){
|
||||
|
||||
connected++;
|
||||
TelldusCore::Message msg;
|
||||
|
||||
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 "ProtocolComen.h"
|
||||
#include "ProtocolEverflourish.h"
|
||||
#include "ProtocolFineoffset.h"
|
||||
#include "ProtocolFuhaote.h"
|
||||
#include "ProtocolGroup.h"
|
||||
#include "ProtocolHasta.h"
|
||||
#include "ProtocolIkea.h"
|
||||
#include "ProtocolMandolyn.h"
|
||||
#include "ProtocolNexa.h"
|
||||
#include "ProtocolOregon.h"
|
||||
#include "ProtocolRisingSun.h"
|
||||
#include "ProtocolSartano.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")) {
|
||||
parameters.push_back("unit");
|
||||
|
||||
|
||||
} else if (TelldusCore::comparei(protocolName, L"group")) {
|
||||
parameters.push_back("devices");
|
||||
|
||||
|
||||
} else if (TelldusCore::comparei(protocolName, L"scene")) {
|
||||
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> retval;
|
||||
std::string decoded = "";
|
||||
|
||||
|
||||
ControllerMessage dataMsg(fullData);
|
||||
if( TelldusCore::comparei(dataMsg.protocol(), L"arctech") ) {
|
||||
decoded = ProtocolNexa::decodeData(dataMsg);
|
||||
|
@ -231,12 +234,30 @@ std::list<std::string> Protocol::decodeData(const std::string &fullData) {
|
|||
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") ) {
|
||||
decoded = ProtocolX10::decodeData(dataMsg);
|
||||
if (decoded != "") {
|
||||
retval.push_back(decoded);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 "TellStick.h"
|
||||
#include "Strings.h"
|
||||
#include "common.h"
|
||||
|
||||
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 *>("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 *>("ignoreControllerConfirmation"), const_cast<char *>("false"), CFGF_NONE),
|
||||
CFG_SEC(const_cast<char *>("device"), device_opts, CFGF_MULTI),
|
||||
CFG_END()
|
||||
};
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include "Settings.h"
|
||||
#include "Strings.h"
|
||||
#include <Windows.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "common.h"
|
||||
|
||||
#include "../client/telldus-core.h"
|
||||
|
||||
|
@ -93,9 +95,8 @@ int Settings::addDevice() {
|
|||
DWORD dwDisp;
|
||||
intDeviceId = getNextDeviceId();
|
||||
|
||||
std::wostringstream ssRegPath;
|
||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
||||
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||
strCompleteRegPath.append(TelldusCore::intToWstring(intDeviceId));
|
||||
|
||||
if (RegCreateKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hk, &dwDisp)) {
|
||||
//fail
|
||||
|
@ -122,7 +123,7 @@ int Settings::getNextDeviceId() const {
|
|||
DWORD dwLength;
|
||||
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){
|
||||
intReturn = nResult + 1;
|
||||
|
@ -143,9 +144,8 @@ int Settings::getNextDeviceId() const {
|
|||
int Settings::removeDevice(int intDeviceId) {
|
||||
TelldusCore::MutexLocker locker(&mutex);
|
||||
|
||||
std::wostringstream ssRegPath;
|
||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
||||
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||
strCompleteRegPath.append(TelldusCore::intToWstring(intDeviceId));
|
||||
|
||||
long lngSuccess = RegDeleteKey(d->rootKey, strCompleteRegPath.c_str());
|
||||
|
||||
|
@ -157,13 +157,39 @@ int Settings::removeDevice(int intDeviceId) {
|
|||
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 strReturn;
|
||||
HKEY hk;
|
||||
|
||||
std::wostringstream ssRegPath;
|
||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
||||
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||
strCompleteRegPath.append(TelldusCore::intToWstring(intDeviceId));
|
||||
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_QUERY_VALUE, &hk);
|
||||
|
||||
if(lnExists == ERROR_SUCCESS){
|
||||
|
@ -191,9 +217,9 @@ int Settings::setStringSetting(int intDeviceId, const std::wstring &name, const
|
|||
HKEY hk;
|
||||
int ret = TELLSTICK_SUCCESS;
|
||||
|
||||
std::wostringstream ssRegPath;
|
||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
||||
std::wstring bla = TelldusCore::intToWstring(intDeviceId);
|
||||
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||
strCompleteRegPath.append(bla);
|
||||
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_WRITE, &hk);
|
||||
|
||||
if (lnExists == ERROR_SUCCESS){
|
||||
|
@ -223,9 +249,8 @@ int Settings::setIntSetting(int intDeviceId, const std::wstring &name, int value
|
|||
int intReturn = TELLSTICK_ERROR_UNKNOWN;
|
||||
HKEY hk;
|
||||
|
||||
std::wostringstream ssRegPath;
|
||||
ssRegPath << d->strRegPathDevice << intDeviceId;
|
||||
std::wstring strCompleteRegPath = ssRegPath.str();
|
||||
std::wstring strCompleteRegPath = d->strRegPathDevice;
|
||||
strCompleteRegPath.append(TelldusCore::intToWstring(intDeviceId));
|
||||
long lnExists = RegOpenKeyEx(d->rootKey, strCompleteRegPath.c_str(), 0, KEY_WRITE, &hk);
|
||||
if (lnExists == ERROR_SUCCESS) {
|
||||
DWORD dwVal = value;
|
||||
|
|
|
@ -29,8 +29,12 @@ public:
|
|||
|
||||
virtual int firmwareVersion();
|
||||
virtual int pid() const;
|
||||
virtual int vid() const;
|
||||
virtual std::string serial() const;
|
||||
|
||||
bool isOpen() const;
|
||||
bool isSameAsDescriptor(const TellStickDescriptor &d) const;
|
||||
virtual int reset();
|
||||
virtual int send( const std::string &message );
|
||||
bool stillConnected() const;
|
||||
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
//
|
||||
//
|
||||
#include "TellStick.h"
|
||||
#include "common.h"
|
||||
#include "Mutex.h"
|
||||
#include "Settings.h"
|
||||
#include "Strings.h"
|
||||
#include "Log.h"
|
||||
#include "../client/telldus-core.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -20,7 +23,7 @@
|
|||
|
||||
class TellStick::PrivateData {
|
||||
public:
|
||||
bool open, running;
|
||||
bool open, running, ignoreControllerConfirmation;
|
||||
int vid, pid, fwVersion;
|
||||
std::string serial, message;
|
||||
FT_HANDLE ftHandle;
|
||||
|
@ -53,6 +56,8 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
|||
d->pid = td.pid;
|
||||
d->fwVersion = 0;
|
||||
d->serial = td.serial;
|
||||
Settings set;
|
||||
d->ignoreControllerConfirmation = set.getSetting(L"ignoreControllerConfirmation")==L"true";
|
||||
|
||||
char *tempSerial = new char[td.serial.size()+1];
|
||||
#ifdef _WINDOWS
|
||||
|
@ -61,6 +66,7 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
|||
strcpy(tempSerial, td.serial.c_str());
|
||||
FT_SetVIDPID(td.vid, td.pid);
|
||||
#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);
|
||||
delete tempSerial;
|
||||
if (ftStatus == FT_OK) {
|
||||
|
@ -76,10 +82,13 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
|||
setBaud(4800);
|
||||
}
|
||||
this->start();
|
||||
} else {
|
||||
Log::warning("Failed to open TellStick");
|
||||
}
|
||||
}
|
||||
|
||||
TellStick::~TellStick() {
|
||||
Log::warning("Disconnected TellStick (%X/%X) with serial %s", d->vid, d->pid, d->serial.c_str());
|
||||
if (d->running) {
|
||||
TelldusCore::MutexLocker locker(&d->mutex);
|
||||
d->running = false;
|
||||
|
@ -108,6 +117,14 @@ int TellStick::pid() const {
|
|||
return d->pid;
|
||||
}
|
||||
|
||||
int TellStick::vid() const {
|
||||
return d->vid;
|
||||
}
|
||||
|
||||
std::string TellStick::serial() const {
|
||||
return d->serial;
|
||||
}
|
||||
|
||||
bool TellStick::isOpen() const {
|
||||
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() {
|
||||
d->running = true;
|
||||
DWORD dwBytesInQueue = 0;
|
||||
|
@ -186,8 +215,7 @@ int TellStick::send( const std::string &strMessage ) {
|
|||
if (!d->open) {
|
||||
return TELLSTICK_ERROR_NOT_FOUND;
|
||||
}
|
||||
bool c = true;
|
||||
|
||||
|
||||
//This lock does two things
|
||||
// 1 Prevents two calls from different threads to this function
|
||||
// 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;
|
||||
ftStatus = FT_Write(d->ftHandle, tempMessage, (DWORD)strMessage.length(), &bytesWritten);
|
||||
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);
|
||||
if (ftStatus == FT_OK) {
|
||||
if (bytesRead == 1) {
|
||||
if (in == '\n') {
|
||||
break;
|
||||
return TELLSTICK_SUCCESS;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else { //Timeout
|
||||
c = false;
|
||||
return TELLSTICK_ERROR_COMMUNICATION;
|
||||
}
|
||||
} 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 {
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <ftdi.h>
|
||||
#include "Thread.h"
|
||||
#include "Mutex.h"
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
#include "Strings.h"
|
||||
#include "common.h"
|
||||
|
||||
|
@ -31,7 +33,7 @@ typedef int DWORD;
|
|||
|
||||
class TellStick::PrivateData {
|
||||
public:
|
||||
bool open;
|
||||
bool open, ignoreControllerConfirmation;
|
||||
int vid, pid, fwVersion;
|
||||
std::string serial, message;
|
||||
ftdi_context ftHandle;
|
||||
|
@ -51,9 +53,13 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
|||
d->serial = td.serial;
|
||||
d->running = false;
|
||||
|
||||
Settings set;
|
||||
d->ignoreControllerConfirmation = set.getSetting(L"ignoreControllerConfirmation")==L"true";
|
||||
|
||||
ftdi_init(&d->ftHandle);
|
||||
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());
|
||||
if (ret < 0) {
|
||||
ftdi_deinit(&d->ftHandle);
|
||||
|
@ -62,6 +68,7 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
|||
d->open = true;
|
||||
ftdi_usb_reset( &d->ftHandle );
|
||||
ftdi_disable_bitbang( &d->ftHandle );
|
||||
ftdi_set_latency_timer(&d->ftHandle, 16);
|
||||
|
||||
if (d->open) {
|
||||
|
||||
|
@ -71,10 +78,13 @@ TellStick::TellStick(int controllerId, Event *event, const TellStickDescriptor &
|
|||
this->setBaud(4800);
|
||||
}
|
||||
this->start();
|
||||
} else {
|
||||
Log::warning("Failed to open TellStick");
|
||||
}
|
||||
}
|
||||
|
||||
TellStick::~TellStick() {
|
||||
Log::warning("Disconnected TellStick (%X/%X) with serial %s", d->vid, d->pid, d->serial.c_str());
|
||||
if (d->running) {
|
||||
stop();
|
||||
}
|
||||
|
@ -94,6 +104,14 @@ int TellStick::pid() const {
|
|||
return d->pid;
|
||||
}
|
||||
|
||||
int TellStick::vid() const {
|
||||
return d->vid;
|
||||
}
|
||||
|
||||
std::string TellStick::serial() const {
|
||||
return d->serial;
|
||||
}
|
||||
|
||||
bool TellStick::isOpen() const {
|
||||
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() {
|
||||
int dwBytesRead = 0;
|
||||
unsigned char buf[1024]; // = 0;
|
||||
|
@ -186,33 +212,44 @@ int TellStick::send( const std::string &strMessage ) {
|
|||
if(ret < 0) {
|
||||
c = false;
|
||||
} else if(ret != strMessage.length()) {
|
||||
fprintf(stderr, "weird send length? retval %i instead of %d\n",
|
||||
ret, (int)strMessage.length());
|
||||
Log::debug("Weird send length? retval %i instead of %d\n", ret, (int)strMessage.length());
|
||||
}
|
||||
|
||||
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;
|
||||
while(c && --retrycnt) {
|
||||
while(--retrycnt) {
|
||||
ret = ftdi_read_data( &d->ftHandle, &in, 1);
|
||||
if (ret > 0) {
|
||||
if (in == '\n') {
|
||||
break;
|
||||
return TELLSTICK_SUCCESS;
|
||||
}
|
||||
} else if(ret == 0) { // No data available
|
||||
usleep(100);
|
||||
} else { //Error
|
||||
c = false;
|
||||
Log::debug("Broken pipe on read");
|
||||
return TELLSTICK_ERROR_BROKEN_PIPE;
|
||||
}
|
||||
}
|
||||
if (!retrycnt) {
|
||||
c = false;
|
||||
}
|
||||
if (!c) {
|
||||
return TELLSTICK_ERROR_COMMUNICATION;
|
||||
}
|
||||
return TELLSTICK_SUCCESS;
|
||||
|
||||
return TELLSTICK_ERROR_COMMUNICATION;
|
||||
}
|
||||
|
||||
void TellStick::setBaud(int baud) {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "ControllerManager.h"
|
||||
#include "ControllerListener.h"
|
||||
#include "EventUpdateManager.h"
|
||||
#include "Timer.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <list>
|
||||
|
@ -39,6 +41,10 @@ void TelldusMain::deviceInsertedOrRemoved(int vid, int pid, bool inserted) {
|
|||
void TelldusMain::start(void) {
|
||||
EventRef clientEvent = 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());
|
||||
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){
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "TelldusWinService_win.h"
|
||||
#include "TelldusMain.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <Dbt.h>
|
||||
#include <string>
|
||||
|
@ -111,6 +112,13 @@ DWORD WINAPI TelldusWinService::serviceControlHandler( DWORD controlCode, DWORD
|
|||
void WINAPI TelldusWinService::serviceMain( DWORD argc, TCHAR* argv[] ) {
|
||||
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
|
||||
instance.serviceStatus.dwServiceType = SERVICE_WIN32;
|
||||
instance.serviceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||
|
@ -140,8 +148,13 @@ void WINAPI TelldusWinService::serviceMain( DWORD argc, TCHAR* argv[] ) {
|
|||
devInterface.dbcc_classguid = GUID_DEVINTERFACE_USBRAW;
|
||||
HDEVNOTIFY deviceNotificationHandle = RegisterDeviceNotificationW(instance.serviceStatusHandle, &devInterface, DEVICE_NOTIFY_SERVICE_HANDLE);
|
||||
|
||||
Log::notice("TelldusService started");
|
||||
|
||||
//Start our main-loop
|
||||
instance.tm->start();
|
||||
|
||||
Log::notice("TelldusService stopping");
|
||||
Log::destroy();
|
||||
|
||||
// service was stopped
|
||||
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 "Log.h"
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
TelldusMain tm;
|
||||
|
||||
void shutdownHandler(int onSignal) {
|
||||
printf("Shutting down\n");
|
||||
Log::notice("Shutting down");
|
||||
tm.stop();
|
||||
}
|
||||
|
||||
void sigpipeHandler(int onSignal) {
|
||||
printf("SIGPIPE received\n");
|
||||
Log::notice("SIGPIPE received");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -19,7 +19,10 @@ int main(int argc, char **argv) {
|
|||
signal(SIGINT, shutdownHandler);
|
||||
signal(SIGPIPE, sigpipeHandler);
|
||||
|
||||
Log::notice("telldusd started");
|
||||
tm.start();
|
||||
printf("telldusd stopped gracefully\n");
|
||||
Log::notice("telldusd stopped gracefully");
|
||||
|
||||
Log::destroy();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
|
@ -12,6 +11,7 @@
|
|||
|
||||
#include "Settings.h"
|
||||
#include "Strings.h"
|
||||
#include "Log.h"
|
||||
|
||||
#define DAEMON_NAME "telldusd"
|
||||
#define PID_FILE "/var/run/" DAEMON_NAME ".pid"
|
||||
|
@ -21,19 +21,19 @@ TelldusMain tm;
|
|||
void signalHandler(int sig) {
|
||||
switch(sig) {
|
||||
case SIGHUP:
|
||||
syslog(LOG_WARNING, "Received SIGHUP signal.");
|
||||
Log::warning("Received SIGHUP signal.");
|
||||
break;
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
syslog(LOG_WARNING, "Received SIGTERM or SIGINT signal.");
|
||||
syslog(LOG_WARNING, "Shutting down");
|
||||
Log::warning("Received SIGTERM or SIGINT signal.");
|
||||
Log::warning("Shutting down");
|
||||
tm.stop();
|
||||
break;
|
||||
case SIGPIPE:
|
||||
syslog(LOG_WARNING, "Received SIGPIPE signal.");
|
||||
Log::warning("Received SIGPIPE signal.");
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_WARNING, "Unhandled signal (%d) %s", sig, strsignal(sig));
|
||||
Log::warning("Unhandled signal (%d) %s", sig, strsignal(sig));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -46,17 +46,19 @@ int main(int argc, char **argv) {
|
|||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "--nodaemon") == 0) {
|
||||
deamonize = false;
|
||||
}
|
||||
if (strcmp(argv[i], "--help") == 0) {
|
||||
Log::setLogOutput(Log::StdOut);
|
||||
} else if (strcmp(argv[i], "--help") == 0) {
|
||||
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");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
if (strcmp(argv[i], "--version") == 0) {
|
||||
} else if (strcmp(argv[i], "--version") == 0) {
|
||||
printf("telldusd " VERSION "\n\n");
|
||||
printf("Copyright (C) 2011 Telldus Technologies AB\n\n");
|
||||
printf("Written by Micke Prag <micke.prag@telldus.se>\n");
|
||||
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);
|
||||
fclose(fd);
|
||||
} 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_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
setlogmask(LOG_UPTO(LOG_INFO));
|
||||
openlog(DAEMON_NAME, LOG_CONS, LOG_USER);
|
||||
|
||||
syslog(LOG_NOTICE, "%s daemon starting up", DAEMON_NAME);
|
||||
Log::notice("%s daemon starting up", DAEMON_NAME);
|
||||
|
||||
if (deamonize) {
|
||||
/* Change the file mode mask */
|
||||
|
@ -115,14 +114,14 @@ int main(int argc, char **argv) {
|
|||
if (grp) {
|
||||
setgid(grp->gr_gid);
|
||||
} 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);
|
||||
}
|
||||
struct passwd *pw = getpwnam(user.c_str());
|
||||
if (pw) {
|
||||
setuid( pw->pw_uid );
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +138,6 @@ int main(int argc, char **argv) {
|
|||
|
||||
tm.start();
|
||||
|
||||
syslog(LOG_NOTICE, "%s daemon exited", DAEMON_NAME);
|
||||
Log::notice("%s daemon exited", DAEMON_NAME);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
user = "nobody"
|
||||
group = "plugdev"
|
||||
ignoreControllerConfirmation = "false"
|
||||
device {
|
||||
id = 1
|
||||
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"
|
||||
ID_VENDOR_ID=="1781", SUBSYSTEM=="usb", ACTION=="remove" 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"
|
||||
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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctime>
|
||||
#include "../client/telldus-core.h"
|
||||
|
||||
const int SUPPORTED_METHODS =
|
||||
|
@ -21,7 +22,7 @@ void print_usage( char *name ) {
|
|||
printf(" [ --raw input ]\n");
|
||||
printf("\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(" --help (-h short option)\n");
|
||||
printf(" Shows this screen.\n");
|
||||
|
@ -77,6 +78,7 @@ void print_version() {
|
|||
}
|
||||
|
||||
void print_device( int index ) {
|
||||
tdInit();
|
||||
int intId = tdGetDeviceId(index);
|
||||
char *name = tdGetName(intId);
|
||||
printf("%i\t%s\t", intId, name);
|
||||
|
@ -101,13 +103,14 @@ void print_device( int index ) {
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
void list_devices() {
|
||||
int list_devices() {
|
||||
tdInit();
|
||||
int intNum = tdGetNumberOfDevices();
|
||||
if (intNum < 0) {
|
||||
char *errorString = tdGetErrorString(intNum);
|
||||
fprintf(stderr, "Error fetching devices: %s\n", errorString);
|
||||
tdReleaseString(errorString);
|
||||
return;
|
||||
return intNum;
|
||||
}
|
||||
printf("Number of devices: %i\n", intNum);
|
||||
int i = 0;
|
||||
|
@ -115,9 +118,51 @@ void list_devices() {
|
|||
print_device( 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 ) {
|
||||
tdInit();
|
||||
int deviceId = atoi(device);
|
||||
if (deviceId == 0) { //Try to find the id from the name
|
||||
int intNum = tdGetNumberOfDevices();
|
||||
|
@ -137,11 +182,12 @@ int find_device( char *device ) {
|
|||
return deviceId;
|
||||
}
|
||||
|
||||
void switch_device( bool turnOn, char *device ) {
|
||||
int switch_device( bool turnOn, char *device ) {
|
||||
tdInit();
|
||||
int deviceId = find_device( device );
|
||||
if (deviceId == 0) {
|
||||
printf("Device '%s', not found!\n", device);
|
||||
return;
|
||||
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
char *name = tdGetName( deviceId );
|
||||
|
@ -158,17 +204,19 @@ void switch_device( bool turnOn, char *device ) {
|
|||
|
||||
printf(" - %s\n", 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 );
|
||||
if (deviceId == 0) {
|
||||
printf("Device '%s', not found!\n", device);
|
||||
return;
|
||||
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
if (level < 0 || level > 255) {
|
||||
printf("Level %i out of range!\n", level);
|
||||
return;
|
||||
return TELLSTICK_ERROR_SYNTAX;
|
||||
}
|
||||
|
||||
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);
|
||||
tdReleaseString(name);
|
||||
tdReleaseString(errorString);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void bell_device( char *device ) {
|
||||
int bell_device( char *device ) {
|
||||
tdInit();
|
||||
int deviceId = find_device( device );
|
||||
if (deviceId == 0) {
|
||||
printf("Device '%s', not found!\n", device);
|
||||
return;
|
||||
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
char *name = tdGetName( deviceId );
|
||||
|
@ -192,13 +242,15 @@ void bell_device( char *device ) {
|
|||
printf("Sending bell to: %i %s - %s\n", deviceId, name, errorString);
|
||||
tdReleaseString(name);
|
||||
tdReleaseString(errorString);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void learn_device( char *device ) {
|
||||
int learn_device( char *device ) {
|
||||
tdInit();
|
||||
int deviceId = find_device( device );
|
||||
if (deviceId == 0) {
|
||||
printf("Device '%s', not found!\n", device);
|
||||
return;
|
||||
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
char *name = tdGetName( deviceId );
|
||||
|
@ -207,9 +259,11 @@ void learn_device( char *device ) {
|
|||
printf("Learning device: %i %s - %s\n", deviceId, name, errorString);
|
||||
tdReleaseString(name);
|
||||
tdReleaseString(errorString);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void send_raw_command( char *command ) {
|
||||
int send_raw_command( char *command ) {
|
||||
tdInit();
|
||||
const int MAX_LENGTH = 100;
|
||||
char msg[MAX_LENGTH];
|
||||
|
||||
|
@ -221,7 +275,7 @@ void send_raw_command( char *command ) {
|
|||
fd = fopen(command, "r");
|
||||
if (fd == NULL) {
|
||||
printf("Error opening file %s\n", command);
|
||||
return;
|
||||
return TELLSTICK_ERROR_UNKNOWN;
|
||||
}
|
||||
fgets(msg, MAX_LENGTH, fd);
|
||||
}
|
||||
|
@ -230,6 +284,7 @@ void send_raw_command( char *command ) {
|
|||
char *errorString = tdGetErrorString(retval);
|
||||
printf("Sending raw command: %s\n", errorString);
|
||||
tdReleaseString(errorString);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@ -253,48 +308,56 @@ int main(int argc, char **argv)
|
|||
|
||||
if (argc < 2) {
|
||||
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) {
|
||||
case 'b' :
|
||||
bell_device( &optarg[0] );
|
||||
success = bell_device( &optarg[0] );
|
||||
break;
|
||||
case 'd' :
|
||||
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;
|
||||
case 'f' :
|
||||
switch_device(false, &optarg[0]);
|
||||
success = switch_device(false, &optarg[0]);
|
||||
break;
|
||||
case 'h' :
|
||||
print_usage( argv[0] );
|
||||
break;
|
||||
success = TELLSTICK_SUCCESS;
|
||||
case 'i' :
|
||||
print_version( );
|
||||
break;
|
||||
success = TELLSTICK_SUCCESS;
|
||||
case 'l' :
|
||||
list_devices();
|
||||
success = list_devices();
|
||||
break;
|
||||
case 'n' :
|
||||
switch_device(true, &optarg[0]);
|
||||
success = switch_device(true, &optarg[0]);
|
||||
break;
|
||||
case 'e' :
|
||||
learn_device(&optarg[0]);
|
||||
success = learn_device(&optarg[0]);
|
||||
break;
|
||||
case 'r' :
|
||||
send_raw_command(&optarg[0]);
|
||||
success = send_raw_command(&optarg[0]);
|
||||
break;
|
||||
case 'v' :
|
||||
level = atoi( &optarg[0] );
|
||||
break;
|
||||
default :
|
||||
print_usage( argv[0] );
|
||||
return -1;
|
||||
success = TELLSTICK_ERROR_SYNTAX;
|
||||
}
|
||||
|
||||
if(success != TELLSTICK_SUCCESS){
|
||||
returnSuccess = success; //return last error message
|
||||
}
|
||||
}
|
||||
tdClose(); //Cleaning up
|
||||
return 0;
|
||||
return -returnSuccess;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@ LiveMessageToken::LiveMessageToken(const QString &value) {
|
|||
stringVal = value;
|
||||
}
|
||||
|
||||
LiveMessageToken::LiveMessageToken(int value) {
|
||||
valueType = Int;
|
||||
intVal = value;
|
||||
}
|
||||
|
||||
QByteArray LiveMessageToken::toByteArray() const {
|
||||
if (valueType == Int) {
|
||||
return QString("i%1s").arg(intVal, 0, 16).toUtf8();
|
||||
|
@ -122,7 +127,7 @@ void LiveMessageTokenScriptWrapper::add(LiveMessageTokenScriptWrapper *t) {
|
|||
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) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
@ -132,6 +137,16 @@ int LiveMessageTokenScriptWrapper::getInt(const QString &key, int defaultValue)
|
|||
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 {
|
||||
return p_token.intVal;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ public:
|
|||
|
||||
LiveMessageToken();
|
||||
LiveMessageToken(const QString &value);
|
||||
LiveMessageToken(int value);
|
||||
QByteArray toByteArray() const;
|
||||
static LiveMessageToken parseToken(const QByteArray &string, int* start);
|
||||
|
||||
|
@ -34,13 +35,14 @@ public:
|
|||
public slots:
|
||||
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;
|
||||
|
||||
void set(const QString &key, int value);
|
||||
void set(const QString &key, const QString &value);
|
||||
|
||||
|
||||
private:
|
||||
LiveMessageToken p_token;
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
class Server;
|
||||
|
||||
QSslSocket *socket;
|
||||
QTimer timer;
|
||||
QTimer pingTimer, pongTimer;
|
||||
bool registered;
|
||||
QUrl registerUrl;
|
||||
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(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
|
||||
|
||||
d->timer.setInterval(60000); //Once a minute
|
||||
connect(&d->timer, SIGNAL(timeout()), this, SLOT(pingServer()));
|
||||
d->pingTimer.setInterval(120000); //Two minutes
|
||||
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);
|
||||
connect(d->manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(serverAssignReply(QNetworkReply*)));
|
||||
|
@ -102,6 +105,8 @@ void LiveObject::readyRead() {
|
|||
//qDebug() << "HASH mismatch!" << msg->name();
|
||||
return;
|
||||
}
|
||||
d->pongTimer.stop();
|
||||
d->pongTimer.start();
|
||||
|
||||
if (msg->name() == "") {
|
||||
return;
|
||||
|
@ -122,6 +127,14 @@ void LiveObject::readyRead() {
|
|||
s.setValue("Live/UUID", d->uuid);
|
||||
emit notRegistered();
|
||||
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 {
|
||||
emit messageReceived(msg.data());
|
||||
}
|
||||
|
@ -132,7 +145,7 @@ void LiveObject::refreshServerList() {
|
|||
emit statusChanged("Discover servers");
|
||||
d->serverList.clear();
|
||||
QUrl url(TELLDUS_LIVE_URI);
|
||||
QPair<QString, QString> version("protocolVersion", "1");
|
||||
QPair<QString, QString> version("protocolVersion", "2");
|
||||
QList<QPair<QString, QString> > query;
|
||||
query.append(version);
|
||||
url.setQueryItems(query);
|
||||
|
@ -156,6 +169,8 @@ void LiveObject::sendMessage(const LiveMessage &message) {
|
|||
|
||||
d->socket->write(msg.toByteArray());
|
||||
d->socket->flush();
|
||||
d->pingTimer.stop();
|
||||
d->pingTimer.start();
|
||||
}
|
||||
|
||||
void LiveObject::sendMessage(LiveMessage *message) {
|
||||
|
@ -170,7 +185,8 @@ void LiveObject::p_connected() {
|
|||
QSettings settings;
|
||||
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");
|
||||
|
||||
LiveMessageToken token;
|
||||
|
@ -188,7 +204,12 @@ void LiveObject::p_connected() {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -198,11 +219,12 @@ void LiveObject::error( QAbstractSocket::SocketError socketError ) {
|
|||
|
||||
void LiveObject::stateChanged( QAbstractSocket::SocketState socketState ) {
|
||||
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()));
|
||||
emit statusChanged("Reconnecting in " + QString::number(timeout) + " seconds...");
|
||||
} else if (socketState == QAbstractSocket::ConnectingState) {
|
||||
emit statusChanged("Connecting...");
|
||||
emit errorChanged("");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,8 +250,10 @@ void LiveObject::sslErrors( const QList<QSslError> & errors ) {
|
|||
void LiveObject::serverAssignReply( QNetworkReply *r ) {
|
||||
r->deleteLater();
|
||||
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 statusChanged("Error retrieving server list");
|
||||
emit statusChanged("Retrying in " + QString::number(timeout) + " seconds...");
|
||||
QTimer::singleShot(timeout * 1000, this, SLOT(connectToServer()));
|
||||
return;
|
||||
}
|
||||
QXmlStreamReader xml(r);
|
||||
|
@ -253,7 +277,7 @@ void LiveObject::serverAssignReply( QNetworkReply *r ) {
|
|||
d->serverRefreshTime = QDateTime::currentDateTime();
|
||||
QTimer::singleShot(0, this, SLOT(connectToServer()));
|
||||
} 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 statusChanged("Retrying in " + QString::number(timeout) + " seconds...");
|
||||
QTimer::singleShot(timeout * 1000, this, SLOT(connectToServer()));
|
||||
|
@ -270,7 +294,7 @@ QByteArray LiveObject::signatureForMessage( const QByteArray &message ) {
|
|||
LiveMessageToken LiveObject::generateVersionToken() {
|
||||
LiveMessageToken token;
|
||||
token.valueType = LiveMessageToken::Dictionary;
|
||||
token.dictVal["protocol"] = LiveMessageToken("1");
|
||||
token.dictVal["protocol"] = LiveMessageToken(2);
|
||||
token.dictVal["version"] = LiveMessageToken(TELLDUS_CENTER_VERSION);
|
||||
#if defined(Q_WS_WIN)
|
||||
token.dictVal["os"] = LiveMessageToken("windows");
|
||||
|
@ -314,3 +338,7 @@ LiveMessageToken LiveObject::generateVersionToken() {
|
|||
#endif
|
||||
return token;
|
||||
}
|
||||
|
||||
void LiveObject::pongTimeout() {
|
||||
this->disconnect();
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ private slots:
|
|||
void p_connected();
|
||||
void p_disconnected();
|
||||
void readyRead();
|
||||
void pongTimeout();
|
||||
void error( QAbstractSocket::SocketError socketError );
|
||||
void stateChanged( QAbstractSocket::SocketState socketState );
|
||||
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