MySensors Library & Examples  2.3.2-62-ge298769
PJONInteractiveRouter.h
1 
2 /*-O//\ __ __
3  |-gfo\ |__| | | | |\ | ®
4  |!y°o:\ | __| |__| | \| 13.0
5  |y"s§+`\ multi-master, multi-media bus network protocol
6  /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo [email protected]
7  |+/:ngr-*.`\
8  |5/:%&-a3f.:;\
9  \+//u/+g%{osv,,\
10  \=+&/osw+olds.\\
11  \:/+-.-°-:+oss\
12  | | \oy\\
13  > <
14 ______-| |-__________________________________________________________________
15 
16 PJONInteractiveRouter has been contributed by Fred Larsen.
17 
18 This class adds functionality to the PJONSwitch, PJONRouter, PJONDynamicRouter
19 and potential future classes derived from them. This functionality allows a
20 switch or router to have it's own device id and send and receive packets as a
21 normal device, but to and from multiple buses.
22 
23 It also allows the device to listen to all packets passing through between
24 buses.
25 
26 Probably it is wise to use this functionality only on routers using
27 strategies that are not timing-critical, for example on buffered media like
28 serial or Ethernet. If used on timing-critical strategies like SWBB, the
29 receiver callback should be really fast.
30 _____________________________________________________________________________
31 
32 This software is experimental and it is distributed "AS IS" without any
33 warranty, use it at your own risk.
34 
35 Copyright 2010-2020 by Giovanni Blu Mitolo [email protected]
36 
37 Licensed under the Apache License, Version 2.0 (the "License");
38 you may not use this file except in compliance with the License.
39 You may obtain a copy of the License at
40 
41  http://www.apache.org/licenses/LICENSE-2.0
42 
43 Unless required by applicable law or agreed to in writing, software
44 distributed under the License is distributed on an "AS IS" BASIS,
45 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46 See the License for the specific language governing permissions and
47 limitations under the License. */
48 
49 #pragma once
50 #include <PJONDynamicRouter.h>
51 #include <PJONVirtualBusRouter.h>
52 
53 typedef void (* PJON_Send_Notification)(
54  const uint8_t * const payload,
55  const uint16_t length,
56  const uint8_t receiver_bus,
57  const uint8_t sender_bus,
58  const PJON_Packet_Info &packet_info
59 );
60 
61 template<class RouterClass = PJONSwitch>
62 class PJONInteractiveRouter : public RouterClass
63 {
64 protected:
65  void *custom_pointer = NULL;
66  PJON_Receiver receiver = NULL;
67  PJON_Error error = NULL;
68  PJON_Send_Notification send_notification = NULL;
69  bool router = false;
70 
71  virtual void dynamic_receiver_function(uint8_t *payload, uint16_t length,
72  const PJON_Packet_Info &packet_info)
73  {
74  // Handle packets to this device, with user-supplied callback and custom ptr
75  // (If this device has a device id on the source bus, and it is equal to
76  // the packets receiver_id, the packet is for this device.)
77  bool packet_is_for_me = (
78  RouterClass::buses[RouterClass::current_bus]->tx.id != PJON_NOT_ASSIGNED &&
79  memcmp(RouterClass::buses[RouterClass::current_bus]->tx.bus_id, packet_info.rx.bus_id, 4) == 0 &&
80  RouterClass::buses[RouterClass::current_bus]->tx.id == packet_info.rx.id
81  );
82 
83  // Take care of other's packets
84  if(!packet_is_for_me) {
85  RouterClass::dynamic_receiver_function(payload, length, packet_info);
86  } else if(packet_info.header & PJON_ACK_REQ_BIT) {
87  RouterClass::buses[RouterClass::current_bus]->send_acknowledge();
88  }
89  // Call the receive callback _after_ the packet has been delivered
90  if(router || packet_is_for_me) {
91  // The packet is for ME :-)
92  PJON_Packet_Info p_i;
93  memcpy(&p_i, &packet_info, sizeof(PJON_Packet_Info));
94  p_i.custom_pointer = custom_pointer;
95  if(receiver) {
96  receiver(payload, length, p_i);
97  }
98  }
99  }
100 
101  virtual void dynamic_error_function(uint8_t code, uint16_t data)
102  {
103  RouterClass::dynamic_error_function(code, data);
104 
105  // Call any user registered error function
106  if(error) {
107  error(code, data, custom_pointer);
108  }
109  }
110 
111  virtual void send_packet(const uint8_t *payload, const uint16_t length,
112  const uint8_t receiver_bus, const uint8_t sender_bus,
113  bool &ack_sent, const PJON_Packet_Info &packet_info)
114  {
115  RouterClass::send_packet(payload, length, receiver_bus, sender_bus, ack_sent, packet_info);
116 
117  // Call any user registered send notification function
118  if (send_notification) {
119  send_notification(payload, length, receiver_bus, sender_bus, packet_info);
120  }
121  }
122 
123 public:
124  PJONInteractiveRouter() : RouterClass() {}
126  uint8_t bus_count,
127  PJONAny* const buses[],
128  uint8_t default_gateway = PJON_NOT_ASSIGNED)
129  : RouterClass(bus_count, buses, default_gateway) {}
130 
131  void set_receiver(PJON_Receiver r)
132  {
133  receiver = r;
134  };
135 
136  void set_error(PJON_Error e)
137  {
138  error = e;
139  };
140 
141  void set_send_notification(PJON_Send_Notification s)
142  {
143  send_notification = s;
144  };
145 
146  void set_custom_ptr(void *custom_ptr)
147  {
148  custom_pointer = custom_ptr;
149  };
150 
151  void send_packet(
152  const uint8_t *payload,
153  uint16_t length,
154  const PJON_Packet_Info &packet_info
155  )
156  {
157  dynamic_receiver_function(payload, length, packet_info);
158  };
159 
160  // Deliver every packet to receiver callback, or just for this device?
161  void set_router(bool on)
162  {
163  router = on;
164  };
165 };
166 
167 // Specialized class to simplify declaration when using 2 buses
168 template<class A, class B, class RouterClass = PJONSwitch>
170 {
171  StrategyLink<A> linkA;
172  StrategyLink<B> linkB;
173  PJONAny busA, busB;
174 public:
175  PJONInteractiveRouter2(uint8_t default_gateway = PJON_NOT_ASSIGNED)
176  {
177  PJON<Any>* buses[2] = { &busA, &busB };
178  PJONSimpleSwitch<Any>::connect_buses(2, buses, default_gateway);
179  busA.set_link(&linkA);
180  busB.set_link(&linkB);
181  };
182 
183  PJONAny &get_bus(const uint8_t ix)
184  {
185  return ix == 0 ? busA : busB;
186  }
187 
188  A &get_strategy_0()
189  {
190  return linkA.strategy;
191  }
192  B &get_strategy_1()
193  {
194  return linkB.strategy;
195  }
196 };
197 
198 // Specialized class to simplify declaration when using 3 buses
199 template<class A, class B, class C, class RouterClass = PJONSwitch>
201 {
202  StrategyLink<A> linkA;
203  StrategyLink<B> linkB;
204  StrategyLink<C> linkC;
205  PJONAny busA, busB, busC;
206 public:
207  PJONInteractiveRouter3(uint8_t default_gateway = PJON_NOT_ASSIGNED)
208  {
209  PJON<Any>* buses[3] = { &busA, &busB, &busC };
210  PJONSimpleSwitch<Any>::connect_buses(3, buses, default_gateway);
211  busA.set_link(&linkA);
212  busB.set_link(&linkB);
213  busC.set_link(&linkC);
214  };
215 
216  PJONAny &get_bus(const uint8_t ix)
217  {
218  return ix == 0 ? busA : (ix == 1 ? busB : busC);
219  }
220 
221  A &get_strategy_0()
222  {
223  return linkA.strategy;
224  }
225  B &get_strategy_1()
226  {
227  return linkB.strategy;
228  }
229  C &get_strategy_2()
230  {
231  return linkC.strategy;
232  }
233 };
PJONInteractiveRouter
Definition: PJONInteractiveRouter.h:62
data
char data[MAX_PAYLOAD_SIZE+1]
Buffer for raw payload data.
Definition: MyMessage.h:654
PJONInteractiveRouter2
Definition: PJONInteractiveRouter.h:169
PJON_Packet_Info
Definition: PJONDefines.h:207
PJONAny
Definition: PJONSwitch.h:44
PJON< Any >
PJONInteractiveRouter3
Definition: PJONInteractiveRouter.h:200
PJONSimpleSwitch
Definition: PJONSimpleSwitch.h:63