HAN-FUN API  1.5.3
This project provides the common implementation of ULE Alliance's HAN-FUN application protocol.
base_app.cpp
Go to the documentation of this file.
1 // =============================================================================
15 // =============================================================================
16 #include <iostream>
17 #include <iomanip>
18 #include <sstream>
19 #include <fstream>
20 #include <string>
21 
22 #include <unistd.h>
23 
24 #include <forward_list>
25 #include <algorithm>
26 
27 #include "hanfun.h"
28 
29 #include "base.h"
30 
31 #include "application.h"
32 
33 #include "common.h"
34 
35 #include "json/json.h"
36 
42 // =============================================================================
43 // Defines
44 // =============================================================================
45 
46 #ifndef HF_APP_CONFIG_FILE
47  #define HF_APP_CONFIG_FILE "./hanfun.json"
48 #endif
49 
50 // =============================================================================
51 // Global Variables
52 // =============================================================================
53 
55 static Base base;
56 
57 // =============================================================================
58 // Commands
59 // =============================================================================
60 
64 COMMAND(ListRegs, "lr", "lr:list registrations.")
65 {
66  UNUSED(args);
67 
68  auto &devices = base.unit0()->device_management()->entries();
69 
70  LOG(APP) << std::setfill(' ');
71  LOG(APP) << "HAN-FUN" << " Registered Devices (" << (int) devices.size() << "):" << NL;
72 
73  /* *INDENT-OFF* */
74  std::for_each(devices.begin(), devices.end(), [](const HF::Core::DeviceManagement::Device &device)
75  {
76  LOG (APP) << (base.link (device.address) != nullptr ? "+ " : "- ");
77  LOG (APP) << std::right << std::setw (5) << device.address << " | ";
78  LOG (APP) << device.uid << NL;
79  });
80  /* *INDENT-ON* */
81 }
82 
86 COMMAND(ListBinds, "lb", "lb:list binds.")
87 {
88  UNUSED(args);
89 
90  HF::Core::BindManagement::Entries &entries = base.unit0()->bind_management()->entries();
91 
92  LOG(APP) << "HAN-FUN Binds (" << entries.size() << "):" << NL;
93  LOG(APP) << "\t" << std::left << std::setfill(' ')
94  << std::setw(16) << "Source"
95  << std::setw(18) << "| Destination"
96  << "| Interface" << std::endl
97  << "\t" << std::setfill('-')
98  << std::setw(15) << "-"
99  << std::setw(18) << " | "
100  << std::setw(12) << " | " << std::endl
101  << std::setfill(' ');
102 
103  /* *INDENT-OFF* */
104  std::for_each (entries.begin (), entries.end (),
105  [](const HF::Core::BindManagement::Entry &entry)
106  {
107  LOG (APP) << "\t" << entry.source << " | " << entry.destination << " | "
108  << entry.itf << NL;
109  });
110  /* *INDENT-ON* */
111 }
112 
116 COMMAND(Register, "r", "r 1 x:register device x.\nr 0:exit registration mode.")
117 {
118  if (args.size() > 0 && args[0] == "0")
119  {
120 #ifdef HF_APP_EXT_REG
121 
122  if (HF::Application::Registration(false))
123  {
124  LOG(INFO) << "Disable Registration mode: SUCCESS" << NL;
125  }
126  else
127  {
128  LOG(WARN) << "Disable Registration mode: FAIL" << NL;
129  }
130 
131 #endif
132  }
133  else if (args.size() > 1 && args[0] == "1")
134  {
135  uint16_t address = STRTOL(args[1]);
136 
137  if (base.unit0()->device_management()->available(address) && address != 0 &&
139  {
140  base.unit0()->device_management()->next_address(address);
141 #ifdef HF_APP_EXT_REG
142 
143  if (HF::Application::Registration(true))
144  {
145  LOG(INFO) << "Enable Registration mode: SUCCESS" << NL;
146  }
147  else
148  {
149  LOG(WARN) << "[HANFUN] Enable Registration mode: FAIL" << NL;
150  }
151 
152 #endif
153  LOG(INFO) << "Next Registration will have address : " << (int) address << NL;
154  }
155  else
156  {
157  LOG(ERROR) << "Registration impossible: address " << (int) address
158  << " not available." << NL;
159  }
160 
161  return;
162  }
163 
164  LOG(APP) << usage(true) << NL;
165 }
166 
170 COMMAND(Deregister, "d", "d x:de-register device x.")
171 {
172  if (args.size() < 1)
173  {
174  LOG(APP) << usage(true) << NL;
175  return;
176  }
177 
178  uint16_t address = STRTOL(args[0]);
179 
180 #ifdef HF_APP_EXT_REG
181  // External de-registration.
182  HF::Application::Deregister(address);
183 #endif
184 
185  /* HAN-FUN de-registration */
186  bool res = base.unit0()->device_management()->deregister(address);
187  LOG(INFO) << "Device " << (int) address << " de-registration: "
188  << (res ? "SUCCESS" : "FAIL") << " !" << NL;
189 }
190 
194 COMMAND(Bind, "b", "b x y:associate device x with device y (bind).")
195 {
196  if (args.size() < 2)
197  {
198  LOG(APP) << usage(true) << NL;
199  return;
200  }
201 
202  uint16_t arg1 = STRTOL(args[0]);
203  uint16_t arg2 = STRTOL(args[1]);
204 
205  uint8_t err = base.bind(arg1, arg2);
206 
207  switch (err)
208  {
209  case 0:
210  {
211  LOG(INFO) << "Bind created !" << NL;
212  break;
213  }
214  case 1:
215  {
216  LOG(WARN) << "Bind already created !" << NL;
217  break;
218  }
219  case 2:
220  case 3:
221  {
222  LOG(ERROR) << "Bind impossible: " << NL;
223 
224  if ((err & 0x01) != 0)
225  {
226  LOG(ERROR) << " - Second device does not exist !" << NL;
227  }
228  else
229  {
230  LOG(ERROR) << " - Fist device does not exist !" << NL;
231  }
232 
233  break;
234  }
235  default:
236  LOG(ERROR) << "No match for bind !" << NL;
237  break;
238  }
239 }
240 
244 COMMAND(Unbind, "u", "u x y:unbind device x with y.")
245 {
246  UNUSED(args);
247 
248  if (args.size() < 2)
249  {
250  LOG(APP) << usage(true) << NL;
251  return;
252  }
253 
254  uint16_t arg1 = STRTOL(args[0]);
255  uint16_t arg2 = STRTOL(args[1]);
256 
257  if (base.unbind(arg1, arg2))
258  {
259  LOG(INFO) << "Bind: " << arg1 << " - " << arg2 << " removed !" << NL;
260  }
261  else
262  {
263  LOG(ERROR) << "Bind: does not exist !" << NL;
264  }
265 }
266 
270 COMMAND(GlobalBind, "gb", "gb 1:create bind to receive all interface events.\n"
271  "gb 0:remove bind to receive all interface events.")
272 {
273  if (args.size() < 1)
274  {
275  LOG(APP) << usage(true) << NL;
276  return;
277  }
278 
279  uint16_t arg1 = STRTOL(args[0]);
280 
282  HF::Protocol::Address source;
283  HF::Protocol::Address dest(0, 1);
284 
285  if (arg1 == 1)
286  {
287  // Bind any interface.
288  auto res = base.unit0()->bind_management()->add(source, dest, itf);
289  assert(res == HF::Common::Result::OK);
290  UNUSED(res);
291  }
292  else if (arg1 == 0)
293  {
294  // Bind any interface.
295  auto res = base.unit0()->bind_management()->remove(source, dest, itf);
296  assert(res == HF::Common::Result::OK);
297  UNUSED(res);
298  }
299  else
300  {
301  LOG(APP) << usage(true) << NL;
302  }
303 }
304 
308 COMMAND(On, "on", "on d u:Send an ON command to device/unit pair.")
309 {
310  if (args.size() < 2)
311  {
312  LOG(APP) << usage(true) << NL;
313  return;
314  }
315 
316  uint16_t arg1 = STRTOL(args[0]);
317  uint16_t arg2 = STRTOL(args[1]);
318 
319  HF::Protocol::Address device(arg1, arg2);
320  base.commands.on_off().on(device);
321 }
322 
326 COMMAND(Off, "off", "off d u:Send an OFF command to device/unit pair.")
327 {
328  if (args.size() < 2)
329  {
330  LOG(APP) << usage(true) << NL;
331  return;
332  }
333 
334  uint16_t arg1 = STRTOL(args[0]);
335  uint16_t arg2 = STRTOL(args[1]);
336 
337  HF::Protocol::Address device(arg1, arg2);
338  base.commands.on_off().off(device);
339 }
340 
344 COMMAND(Toggle, "toggle", "toggle d u:Send a TOGGLE command to device/unit pair.")
345 {
346  if (args.size() < 2)
347  {
348  LOG(APP) << usage(true) << NL;
349  return;
350  }
351 
352  uint16_t arg1 = STRTOL(args[0]);
353  uint16_t arg2 = STRTOL(args[1]);
354 
355  HF::Protocol::Address device(arg1, arg2);
356  base.commands.on_off().toggle(device);
357 }
358 
359 COMMAND(Raw, "raw", "raw <raw data>:simulate receiving a packet from the network.")
360 {
362 
363  data.reserve(args.size());
364 
365  /* *INDENT-OFF* */
366  std::for_each (args.begin (), args.end (), [&data](std::string byte)
367  {
368  uint8_t temp = STRTOL_HEX (byte);
369  data.push_back (temp);
370  });
371  /* *INDENT-ON* */
372 
373  HF::Protocol::Packet packet;
374  uint16_t offset = packet.unpack(data);
375 
376  packet.link = base.link(packet.source.device);
377  base.receive(packet, data, offset);
378 }
379 
383 COMMAND(DevInfo, "di", "di m d:Get device information mandatory attributes.\n"
384  "di a d:Get device information all attributes.")
385 {
386  if (args.size() < 2)
387  {
388  LOG(APP) << usage(true) << NL;
389  return;
390  }
391 
392  uint16_t arg1 = STRTOL(args[1]);
393 
394  HF::Protocol::Address device(arg1, 0);
395 
396  HF::Protocol::Message *msg = nullptr;
397 
398  if (args[0] == "m")
399  {
401  }
402  else if (args[0] == "a")
403  {
405  }
406 
407  if (msg != nullptr)
408  {
409  base.commands.send(device, *msg, nullptr);
410  delete msg;
411  }
412  else
413  {
414  LOG(APP) << usage(true) << NL;
415  }
416 }
417 
418 COMMAND(Links, "ll", "ll :list links.")
419 {
420  UNUSED(args);
421 
422  auto &links = base.links();
423 
424  /* *INDENT-OFF* */
425  std::for_each(links.begin(), links.end(), [](const HF::Transport::Link *link)
426  {
427  LOG (APP) << std::setw (5) << link->address() << " | ";
428  LOG (APP) << link->uid() << NL;
429  });
430  /* *INDENT-ON* */
431 
432 }
433 
434 // =============================================================================
435 // HF::Application::Initialize
436 // =============================================================================
440 // =============================================================================
442 {
443  LOG(TRACE) << __PRETTY_FUNCTION__ << NL;
444 
445  transport.initialize();
446 
447  transport.add(&base);
448 
449  COMMAND_ADD(ListRegs);
450  COMMAND_ADD(ListBinds);
451  COMMAND_ADD(Register);
452  COMMAND_ADD(Deregister);
453  COMMAND_ADD(Bind);
454  COMMAND_ADD(Unbind);
455  COMMAND_ADD(GlobalBind);
456  COMMAND_ADD(On);
457  COMMAND_ADD(Off);
458  COMMAND_ADD(Toggle);
459  COMMAND_ADD(Raw);
460  COMMAND_ADD(DevInfo);
461  COMMAND_ADD(Links);
462 
463  Restore();
464 }
465 
466 // =============================================================================
467 // HF::Application::Save
468 // =============================================================================
472 // =============================================================================
474 {
475  Json::Value root;
476  Json::StyledWriter writer;
477  std::ofstream ofs(HF_APP_CONFIG_FILE);
478 
479  base.unit0()->device_management()->save(root["core"]["device_management"]);
480  base.unit0()->bind_management()->save(root["core"]["bind_management"]);
481 
482  if (ofs.is_open())
483  {
484  ofs << root;
485  ofs.close();
486  }
487 
488  Saved();
489 }
490 
491 // =============================================================================
492 // HF::Application::Restore
493 // =============================================================================
497 // =============================================================================
499 {
500  Json::Reader reader;
501  Json::Value root;
502 
503  std::ifstream ifs(HF_APP_CONFIG_FILE);
504 
505  if (reader.parse(ifs, root, false) == false)
506  {
507  LOG(WARN) << "Reading configuration file !!" << reader.getFormattedErrorMessages() << NL;
508  }
509  else
510  {
511  base.unit0()->device_management()->restore(root["core"]["device_management"]);
512  base.unit0()->bind_management()->restore(root["core"]["bind_management"]);
513  }
514 
515  ifs.close();
516 
517  Restored();
518 }
This class represents a HAN-FUN Concentrator.
Definition: base.h:302
uint16_t unpack(const Common::ByteArray &array, uint16_t offset=0)
Read a message from a ByteArray.
This is the top level include file for the HAN-FUN library.
This file contains the definitions for the HAN-FUN example applications.
void Saved()
Callback indicating that the application configuration has been saved.
Definition: main.cpp:95
uint16_t arg2
Create bind command.
Definition: base_app.cpp:203
Default implementation of the bind entries container.
This class defines the API for the transport layer.
constexpr uint16_t BROADCAST_ADDR
HAN-FUN Broadcast - device address.
Definition: protocol.h:45
Protocol::Message * all()
Create a message that can be used to retrieve all the attributes on a remote device.
#define STRTOL_HEX(X)
Helper macro to convert a std::string into a number (base 16).
Definition: apps/common.h:179
void Restored()
Callback indicating that the application configuration has been restored.
Definition: main.cpp:107
#define COMMAND_ADD(_name)
Helper macro to add a new command to the registry.
Definition: apps/common.h:166
virtual void initialize()=0
Initialize the associated transport layer.
virtual void add(Endpoint *ep)=0
Register the given Endpoint to receive events.
#define STRTOL(X)
Helper macro to convert a std::string into a number (base 10).
Definition: apps/common.h:176
This class represents a byte array.
#define NL
Helper define for new-line and stream clear.
Definition: debug.h:34
#define HF_APP_CONFIG_FILE
JSON database file.
Definition: base_app.cpp:47
CoreServices * unit0() const
Get the unit 0 used by this concentrator device.
Definition: devices.h:910
Network Address.
Definition: protocol.h:201
Network Message.
Definition: protocol.h:60
bool unbind(uint16_t dev_addr_1, uint16_t dev_addr_2)
Remove the binding entry for the given devices.
Definition: base.cpp:667
HAN-FUN Protocol Packet.
Definition: protocol.h:298
This file contains the definition of the Base class that represents the HAN-FUN Concentrator on the a...
HF::Transport::Link * link(uint16_t addr) const
Return the link that can be used to send a packet to the device with the given address.
Any interface UID value.
Definition: interface.h:95
This represents a bind entry data structure.
void receive(HF::Protocol::Packet &packet, HF::Common::ByteArray &payload, uint16_t offset)
Callback to deliver a packet received from the transport layer.
Definition: base.cpp:595
#define UNUSED(x)
Helper macro to remove warning about unused function/method argument.
void Restore()
Restore application configuration.
Definition: base_app.cpp:498
COMMAND(ListRegs, "lr", "lr:list registrations.")
ListRegs List registrations command.
Definition: base_app.cpp:64
This file contains the definitions for the common functionality in the HAN-FUN example applications...
#define LOG(X)
Log messages with the level given by X.
Definition: debug.h:81
uint8_t bind(uint16_t dev_addr_1, uint16_t dev_addr_2)
Create a new bind entry.
Definition: base.cpp:629
Protocol::Message * mandatory()
Create a message that can be used to retrieve the mandatory attributes on a remote device...
void Save()
Save application configuration.
Definition: base_app.cpp:473
uint16_t size() const
Return the number of entries in the container.
void Initialize(HF::Transport::Layer &transport)
Initialize the application.
Definition: base_app.cpp:441