1 //-----------------------------------------------------------------------------
2 //
3 //	Clock.cpp
4 //
5 //	Implementation of the Z-Wave COMMAND_CLASS_CLOCK
6 //
7 //	Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
8 //
9 //	SOFTWARE NOTICE AND LICENSE
10 //
11 //	This file is part of OpenZWave.
12 //
13 //	OpenZWave is free software: you can redistribute it and/or modify
14 //	it under the terms of the GNU Lesser General Public License as published
15 //	by the Free Software Foundation, either version 3 of the License,
16 //	or (at your option) any later version.
17 //
18 //	OpenZWave is distributed in the hope that it will be useful,
19 //	but WITHOUT ANY WARRANTY; without even the implied warranty of
20 //	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 //	GNU Lesser General Public License for more details.
22 //
23 //	You should have received a copy of the GNU Lesser General Public License
24 //	along with OpenZWave.  If not, see <http://www.gnu.org/licenses/>.
25 //
26 //-----------------------------------------------------------------------------
27 
28 #include "command_classes/CommandClasses.h"
29 #include "command_classes/Clock.h"
30 #include "Defs.h"
31 #include "Msg.h"
32 #include "Node.h"
33 #include "Driver.h"
34 #include "platform/Log.h"
35 
36 #include "value_classes/ValueByte.h"
37 #include "value_classes/ValueList.h"
38 
39 using namespace OpenZWave;
40 
41 enum ClockCmd
42 {
43 	ClockCmd_Set	= 0x04,
44 	ClockCmd_Get	= 0x05,
45 	ClockCmd_Report	= 0x06
46 };
47 
48 enum
49 {
50 	ClockIndex_Day = 0,
51 	ClockIndex_Hour,
52 	ClockIndex_Minute
53 };
54 
55 static char const* c_dayNames[] =
56 {
57 	"Invalid",
58 	"Monday",
59 	"Tuesday",
60 	"Wednesday",
61 	"Thursday",
62 	"Friday",
63 	"Saturday",
64 	"Sunday"
65 };
66 
67 //-----------------------------------------------------------------------------
68 // <Clock::RequestState>
69 // Request current state from the device
70 //-----------------------------------------------------------------------------
RequestState(uint32 const _requestFlags,uint8 const _instance,Driver::MsgQueue const _queue)71 bool Clock::RequestState
72 (
73 	uint32 const _requestFlags,
74 	uint8 const _instance,
75 	Driver::MsgQueue const _queue
76 )
77 {
78 	if( _requestFlags & RequestFlag_Dynamic )
79 	{
80 		return RequestValue( _requestFlags, 0, _instance, _queue );
81 	}
82 
83 	return false;
84 }
85 
86 //-----------------------------------------------------------------------------
87 // <Clock::RequestValue>
88 // Request current value from the device
89 //-----------------------------------------------------------------------------
RequestValue(uint32 const _requestFlags,uint8 const _dummy1,uint8 const _instance,Driver::MsgQueue const _queue)90 bool Clock::RequestValue
91 (
92 	uint32 const _requestFlags,
93 	uint8 const _dummy1,	// = 0 (not used)
94 	uint8 const _instance,
95 	Driver::MsgQueue const _queue
96 )
97 {
98 	if ( IsGetSupported() )
99 	{
100 		Msg* msg = new Msg( "ClockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
101 		msg->SetInstance( this, _instance );
102 		msg->Append( GetNodeId() );
103 		msg->Append( 2 );
104 		msg->Append( GetCommandClassId() );
105 		msg->Append( ClockCmd_Get );
106 		msg->Append( GetDriver()->GetTransmitOptions() );
107 		GetDriver()->SendMsg( msg, _queue );
108 		return true;
109 	} else {
110 		Log::Write(  LogLevel_Info, GetNodeId(), "ClockCmd_Get Not Supported on this node");
111 	}
112 	return false;
113 }
114 
115 //-----------------------------------------------------------------------------
116 // <Clock::HandleMsg>
117 // Handle a message from the Z-Wave network
118 //-----------------------------------------------------------------------------
HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)119 bool Clock::HandleMsg
120 (
121 	uint8 const* _data,
122 	uint32 const _length,
123 	uint32 const _instance	// = 1
124 )
125 {
126 	if (ClockCmd_Report == (ClockCmd)_data[0])
127 	{
128 		uint8 day = _data[1] >> 5;
129 		uint8 hour = _data[1] & 0x1f;
130 		uint8 minute = _data[2];
131 
132 		if (day > 7) /* size of c_dayNames */
133 		{
134 			Log::Write (LogLevel_Warning, GetNodeId(), "Day Value was greater than range. Setting to Invalid");
135 			day = 0;
136 		}
137 
138 		Log::Write( LogLevel_Info, GetNodeId(), "Received Clock report: %s %.2d:%.2d", c_dayNames[day], hour, minute );
139 
140 
141 		if( ValueList* dayValue = static_cast<ValueList*>( GetValue( _instance, ClockIndex_Day ) ) )
142 		{
143 			dayValue->OnValueRefreshed( day );
144 			dayValue->Release();
145 		}
146 		if( ValueByte* hourValue = static_cast<ValueByte*>( GetValue( _instance, ClockIndex_Hour ) ) )
147 		{
148 			hourValue->OnValueRefreshed( hour );
149 			hourValue->Release();
150 		}
151 		if( ValueByte* minuteValue = static_cast<ValueByte*>( GetValue( _instance, ClockIndex_Minute ) ) )
152 		{
153 			minuteValue->OnValueRefreshed( minute );
154 			minuteValue->Release();
155 		}
156 		return true;
157 	}
158 
159 	return false;
160 }
161 
162 //-----------------------------------------------------------------------------
163 // <Clock::SetValue>
164 // Set a value in the Z-Wave device
165 //-----------------------------------------------------------------------------
SetValue(Value const & _value)166 bool Clock::SetValue
167 (
168 	Value const& _value
169 )
170 {
171 	bool ret = false;
172 
173 	uint8 instance = _value.GetID().GetInstance();
174 
175 	ValueList* dayValue = static_cast<ValueList*>( GetValue( instance, ClockIndex_Day ) );
176 	ValueByte* hourValue = static_cast<ValueByte*>( GetValue( instance, ClockIndex_Hour ) );
177 	ValueByte* minuteValue = static_cast<ValueByte*>( GetValue( instance, ClockIndex_Minute ) );
178 
179 	if( dayValue && hourValue && minuteValue )
180 	{
181 		if (dayValue->GetItem() == NULL) {
182 			ret = false;
183 		} else {
184 			uint8 day = dayValue->GetItem()->m_value;
185 			if (_value.GetID() == dayValue->GetID()) {
186 				ValueList const * dayvaluetmp = static_cast<ValueList const*>(&_value);
187 				day = dayvaluetmp->GetItem()->m_value;
188 				dayValue->OnValueRefreshed(day);
189 			}
190 			uint8 hour = hourValue->GetValue();
191 			if (_value.GetID() == hourValue->GetID()) {
192 				ValueByte const * hourvaluetmp = static_cast<ValueByte const*>(&_value);
193 				hour = hourvaluetmp->GetValue();
194 				hourValue->OnValueRefreshed(hour);
195 			}
196 			uint8 minute = minuteValue->GetValue();
197 			if (_value.GetID() == minuteValue->GetID()) {
198 				ValueByte const * minuteValuetmp = static_cast<ValueByte const*>(&_value);
199 				minute = minuteValuetmp->GetValue();
200 				minuteValue->OnValueRefreshed(minute);
201 			}
202 
203 
204 			Msg* msg = new Msg( "ClockCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
205 			msg->SetInstance( this, instance );
206 			msg->Append( GetNodeId() );
207 			msg->Append( 4 );
208 			msg->Append( GetCommandClassId() );
209 			msg->Append( ClockCmd_Set );
210 			msg->Append( ( day << 5 ) | hour );
211 			msg->Append( minute );
212 			msg->Append( GetDriver()->GetTransmitOptions() );
213 			GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
214 			ret = true;
215 		}
216 	}
217 
218 	if( dayValue != NULL )
219 	{
220 		dayValue->Release();
221 	}
222 	if( hourValue != NULL )
223 	{
224 		hourValue->Release();
225 	}
226 	if( minuteValue != NULL )
227 	{
228 		minuteValue->Release();
229 	}
230 	return ret;
231 }
232 
233 //-----------------------------------------------------------------------------
234 // <Clock::CreateVars>
235 // Create the values managed by this command class
236 //-----------------------------------------------------------------------------
CreateVars(uint8 const _instance)237 void Clock::CreateVars
238 (
239 	uint8 const _instance
240 )
241 {
242 	if( Node* node = GetNodeUnsafe() )
243 	{
244 		vector<ValueList::Item> items;
245 		for( int i=1; i<=7; ++i )
246 		{
247 			ValueList::Item item;
248 			item.m_label = c_dayNames[i];
249 			item.m_value = i;
250 			items.push_back( item );
251 		}
252 
253 		node->CreateValueList( ValueID::ValueGenre_User, GetCommandClassId(), _instance, ClockIndex_Day, "Day", "", false, false, 1, items, 0, 0 );
254 		node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, ClockIndex_Hour, "Hour", "", false, false, 12, 0 );
255 		node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, ClockIndex_Minute, "Minute", "", false, false, 0, 0 );
256 	}
257 }
258