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 namespace OpenZWave
40 {
41 	namespace Internal
42 	{
43 		namespace CC
44 		{
45 
46 			enum ClockCmd
47 			{
48 				ClockCmd_Set = 0x04,
49 				ClockCmd_Get = 0x05,
50 				ClockCmd_Report = 0x06
51 			};
52 
53 			static char const* c_dayNames[] =
54 			{ "Invalid", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
55 
56 //-----------------------------------------------------------------------------
57 // <Clock::RequestState>
58 // Request current state from the device
59 //-----------------------------------------------------------------------------
RequestState(uint32 const _requestFlags,uint8 const _instance,Driver::MsgQueue const _queue)60 			bool Clock::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue)
61 			{
62 				if (_requestFlags & RequestFlag_Dynamic)
63 				{
64 					return RequestValue(_requestFlags, 0, _instance, _queue);
65 				}
66 
67 				return false;
68 			}
69 
70 //-----------------------------------------------------------------------------
71 // <Clock::RequestValue>
72 // Request current value from the device
73 //-----------------------------------------------------------------------------
RequestValue(uint32 const _requestFlags,uint16 const _dummy1,uint8 const _instance,Driver::MsgQueue const _queue)74 			bool Clock::RequestValue(uint32 const _requestFlags, uint16 const _dummy1,	// = 0 (not used)
75 					uint8 const _instance, Driver::MsgQueue const _queue)
76 			{
77 				if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED))
78 				{
79 					Msg* msg = new Msg("ClockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId());
80 					msg->SetInstance(this, _instance);
81 					msg->Append(GetNodeId());
82 					msg->Append(2);
83 					msg->Append(GetCommandClassId());
84 					msg->Append(ClockCmd_Get);
85 					msg->Append(GetDriver()->GetTransmitOptions());
86 					GetDriver()->SendMsg(msg, _queue);
87 					return true;
88 				}
89 				else
90 				{
91 					Log::Write(LogLevel_Info, GetNodeId(), "ClockCmd_Get Not Supported on this node");
92 				}
93 				return false;
94 			}
95 
96 //-----------------------------------------------------------------------------
97 // <Clock::HandleMsg>
98 // Handle a message from the Z-Wave network
99 //-----------------------------------------------------------------------------
HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)100 			bool Clock::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance	// = 1
101 					)
102 			{
103 				if (ClockCmd_Report == (ClockCmd) _data[0])
104 				{
105 					uint8 day = _data[1] >> 5;
106 					uint8 hour = _data[1] & 0x1f;
107 					uint8 minute = _data[2];
108 
109 					if (day > 7) /* size of c_dayNames */
110 					{
111 						Log::Write(LogLevel_Warning, GetNodeId(), "Day Value was greater than range. Setting to Invalid");
112 						day = 0;
113 					}
114 
115 					Log::Write(LogLevel_Info, GetNodeId(), "Received Clock report: %s %.2d:%.2d", c_dayNames[day], hour, minute);
116 
117 					if (Internal::VC::ValueList* dayValue = static_cast<Internal::VC::ValueList*>(GetValue(_instance, ValueID_Index_Clock::Day)))
118 					{
119 						dayValue->OnValueRefreshed(day);
120 						dayValue->Release();
121 					}
122 					if (Internal::VC::ValueByte* hourValue = static_cast<Internal::VC::ValueByte*>(GetValue(_instance, ValueID_Index_Clock::Hour)))
123 					{
124 						hourValue->OnValueRefreshed(hour);
125 						hourValue->Release();
126 					}
127 					if (Internal::VC::ValueByte* minuteValue = static_cast<Internal::VC::ValueByte*>(GetValue(_instance, ValueID_Index_Clock::Minute)))
128 					{
129 						minuteValue->OnValueRefreshed(minute);
130 						minuteValue->Release();
131 					}
132 					return true;
133 				}
134 
135 				return false;
136 			}
137 
138 //-----------------------------------------------------------------------------
139 // <Clock::SetValue>
140 // Set a value in the Z-Wave device
141 //-----------------------------------------------------------------------------
SetValue(Internal::VC::Value const & _value)142 			bool Clock::SetValue(Internal::VC::Value const& _value)
143 			{
144 				bool ret = false;
145 
146 				uint8 instance = _value.GetID().GetInstance();
147 
148 				Internal::VC::ValueList* dayValue = static_cast<Internal::VC::ValueList*>(GetValue(instance, ValueID_Index_Clock::Day));
149 				Internal::VC::ValueByte* hourValue = static_cast<Internal::VC::ValueByte*>(GetValue(instance, ValueID_Index_Clock::Hour));
150 				Internal::VC::ValueByte* minuteValue = static_cast<Internal::VC::ValueByte*>(GetValue(instance, ValueID_Index_Clock::Minute));
151 
152 				if (dayValue && hourValue && minuteValue)
153 				{
154 					if (dayValue->GetItem() == NULL)
155 					{
156 						ret = false;
157 					}
158 					else
159 					{
160 						uint8 day = dayValue->GetItem()->m_value;
161 						if (_value.GetID() == dayValue->GetID())
162 						{
163 							Internal::VC::ValueList const * dayvaluetmp = static_cast<Internal::VC::ValueList const*>(&_value);
164 							day = dayvaluetmp->GetItem()->m_value;
165 							dayValue->OnValueRefreshed(day);
166 						}
167 						uint8 hour = hourValue->GetValue();
168 						if (_value.GetID() == hourValue->GetID())
169 						{
170 							Internal::VC::ValueByte const * hourvaluetmp = static_cast<Internal::VC::ValueByte const*>(&_value);
171 							hour = hourvaluetmp->GetValue();
172 							hourValue->OnValueRefreshed(hour);
173 						}
174 						uint8 minute = minuteValue->GetValue();
175 						if (_value.GetID() == minuteValue->GetID())
176 						{
177 							Internal::VC::ValueByte const * minuteValuetmp = static_cast<Internal::VC::ValueByte const*>(&_value);
178 							minute = minuteValuetmp->GetValue();
179 							minuteValue->OnValueRefreshed(minute);
180 						}
181 
182 						Msg* msg = new Msg("ClockCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true);
183 						msg->SetInstance(this, instance);
184 						msg->Append(GetNodeId());
185 						msg->Append(4);
186 						msg->Append(GetCommandClassId());
187 						msg->Append(ClockCmd_Set);
188 						msg->Append((day << 5) | hour);
189 						msg->Append(minute);
190 						msg->Append(GetDriver()->GetTransmitOptions());
191 						GetDriver()->SendMsg(msg, Driver::MsgQueue_Send);
192 						ret = true;
193 					}
194 				}
195 
196 				if (dayValue != NULL)
197 				{
198 					dayValue->Release();
199 				}
200 				if (hourValue != NULL)
201 				{
202 					hourValue->Release();
203 				}
204 				if (minuteValue != NULL)
205 				{
206 					minuteValue->Release();
207 				}
208 				return ret;
209 			}
210 
211 //-----------------------------------------------------------------------------
212 // <Clock::CreateVars>
213 // Create the values managed by this command class
214 //-----------------------------------------------------------------------------
CreateVars(uint8 const _instance)215 			void Clock::CreateVars(uint8 const _instance)
216 			{
217 				if (Node* node = GetNodeUnsafe())
218 				{
219 					vector<Internal::VC::ValueList::Item> items;
220 					for (int i = 1; i <= 7; ++i)
221 					{
222 						Internal::VC::ValueList::Item item;
223 						item.m_label = c_dayNames[i];
224 						item.m_value = i;
225 						items.push_back(item);
226 					}
227 
228 					node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Clock::Day, "Day", "", false, false, 1, items, 0, 0);
229 					node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Clock::Hour, "Hour", "", false, false, 12, 0);
230 					node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Clock::Minute, "Minute", "", false, false, 0, 0);
231 				}
232 			}
233 		} // namespace CC
234 	} // namespace Internal
235 } // namespace OpenZWave
236