Skip to content

Commit 88474bd

Browse files
committed
Updated to work with version 7.0 of PJON
1 parent 02f986d commit 88474bd

File tree

15 files changed

+329
-49
lines changed

15 files changed

+329
-49
lines changed

CompositeLink.h

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/* This CompositeLink class transfers PJON packets over one or more Links, having a routing table that specifies which link
2+
must be used to reach a specific device. Devices which have not been registered will be reached through the default link.
3+
4+
A concrete use for this class can be where most devices can be reached through a wire, but some must be reached through
5+
a wireless connection using. And perhaps some others that must be reached through Ethernet (TCP or UDP).
6+
*/
7+
8+
#pragma once
9+
10+
#include <PJONLink.h>
11+
12+
// This define can be set to increase or decrease the max number of registered routes
13+
#ifndef MAX_LINK_ROUTES
14+
#define MAX_LINK_ROUTES 10
15+
#endif
16+
17+
#define MAX_LINKS 5
18+
19+
class CompositeLink : public Link {
20+
Link *default_link = NULL;
21+
int8_t num_links = 0;
22+
Link *links[MAX_LINKS]; // A collection of all registered links in addition to the default
23+
24+
uint8_t num_routes = 0;
25+
uint8_t device_ids[MAX_LINK_ROUTES]; // Each device's id...
26+
uint8_t link_ix[MAX_LINK_ROUTES]; // ...and the index in the links array of the link through which it can be reached
27+
28+
PacketInfo lpi;
29+
long dummy_bus_id = 0;
30+
31+
// Return array position of link if already registered, or -1 if not
32+
int8_t find_link(const Link* link) {
33+
for (int8_t i=0; i<num_links; i++) if (links[i] == link) return i;
34+
return -1;
35+
}
36+
37+
// Find the link to be used for reaching a device
38+
Link *find_link_by_device(uint8_t device_id) {
39+
for (int8_t i=0; i<num_links; i++) if (device_ids[i] == device_id) return links[link_ix[i]];
40+
return default_link;
41+
}
42+
43+
// Locate link or add it, then return is position in the array, -1 if not added.
44+
int8_t register_link(Link *link) {
45+
int8_t ix = find_link(link);
46+
if (ix < 0 && num_links < MAX_LINKS) { // Not present, must be added
47+
links[num_links++] = link;
48+
link->set_receiver(link_receiver_callback, this);
49+
return num_links-1;
50+
}
51+
return ix;
52+
}
53+
54+
static void link_receiver_callback(uint8_t id, const uint8_t *payload, uint16_t length, void *callback_object) {
55+
if (callback_object && ((CompositeLink*)callback_object)->_receiver)
56+
((CompositeLink*)callback_object)->_receiver((uint8_t*)payload, length, ((CompositeLink*)callback_object)->lpi);
57+
}
58+
receiver _receiver = NULL;
59+
60+
public:
61+
62+
CompositeLink() {}
63+
64+
// All devices not having an explicit association to a link will be reached through the default link.
65+
// Note that the default link MUST BE SET.
66+
void set_default_route(Link *link) { default_link = link; default_link.set_receiver(link_receiver_callback, this); }
67+
68+
// Register that a specific device must be reached through a specific link
69+
bool add_route(uint8_t device_id, Link *link) {
70+
if (num_devices >= MAX_LINK_ROUTES) return false;
71+
device_ids[num_devices] = device_id;
72+
link_ix[num_devices] = register_link(link);
73+
if (link_ix[num_devices] < 0) return false; // Could not add link -- too many?
74+
num_devices++;
75+
return true;
76+
}
77+
78+
79+
//**************** Overridden functions below *******************
80+
81+
uint16_t receive() {
82+
for (uint8_t i=0; i<num_links; i++) {
83+
uint16_t v = links[i].receive();
84+
if (v == ACK) return v;
85+
}
86+
return default_link->receive();
87+
}
88+
89+
uint16_t receive(uint32_t duration) {
90+
uint16_t response;
91+
uint32_t time = micros();
92+
while((uint32_t)(micros() - time) <= duration) {
93+
response = receive();
94+
if(response == ACK) return ACK;
95+
}
96+
return response;
97+
};
98+
99+
uint8_t update() {
100+
uint8_t num_packets = 0;
101+
num_packets += default_link->update();
102+
for (uint8_t i=0; i<num_links; i++) num_packets += links[i]->update();
103+
return num_packets;
104+
}
105+
106+
uint16_t send_packet(uint8_t id, const uint8_t *b_id, const char *string, uint16_t length, uint32_t duration, uint8_t header) {
107+
// Remember last packet info
108+
memset(&lpi, 0, sizeof lpi);
109+
lpi.header = header==0 ? SENDER_INFO_BIT | ACK_REQUEST_BIT | MI_PJON_BIT | MI_EXTENDED_HEADER_BIT : header;
110+
lpi.receiver_id = id;
111+
copy_bus_id(lpi.receiver_bus_id, b_id);
112+
lpi.sender_id = get_id();
113+
copy_bus_id(lpi.sender_bus_id, (uint8_t*) &dummy_bus_id);
114+
115+
// Find link and ask it to send
116+
Link *link = find_link_by_device(id);
117+
return link->send_packet(id, b_id, string, length, duration, header);
118+
}
119+
120+
const PacketInfo &get_last_packet_info() const { return lpi; }
121+
uint16_t get_header() const { return lpi.header; }
122+
123+
uint8_t get_id() const { return link.get_id(); }
124+
const uint8_t *get_bus_id() const { return (const uint8_t*) &dummy_bus_id; }
125+
126+
void set_receiver(receiver r) { _receiver = r; }
127+
};
128+

HttpRequests.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
POST /set_jsonstatus.php HTTP/1.0
2+
Content-Type: application/json
3+
Connection: close
4+
Content-Length: 182
5+
{"ghTA":3.20,"ghTE":1.44,"ghTElec":6.50,"ghTG":0.75,"ghHA":92.20,"ghHE":0.88,"ghRain":52.83,"ghLight":0.98,"ghDewPoint":2.06,"ghMotion":0,"ghLastLife":1,"ghUptime":9682,"ghMemErr":0}
6+
7+
8+
193
9+
{"ghTA":3.30,"ghTE":1.50,"ghTElec":6.56,"ghTG":0.75,"ghHA":92.20,"ghHE":0.88,"ghRain":51.86,"ghLight":0.88,"ghDewPoint":2.16,"ghMotion":0,"ghLastLife":0,"ghUptime":9971,"ghMemErr":0,"scan1m":1}

Link.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ struct Link {
99
virtual uint8_t update() = 0;
1010
virtual uint16_t send_packet(uint8_t id, const uint8_t *b_id, const char *string, uint16_t length, uint32_t timeout, uint16_t header) = 0;
1111

12-
virtual const PacketInfo &get_last_packet_info() const = 0;
12+
virtual const PJON_Packet_Info &get_last_packet_info() const = 0;
1313
virtual uint16_t get_header() const = 0;
1414

1515
virtual uint8_t get_id() const = 0;
1616
virtual const uint8_t *get_bus_id() const = 0;
1717

18-
virtual void set_receiver(receiver r) = 0;
18+
virtual void set_receiver(PJON_Receiver r) = 0;
1919
};

ModuleInterface.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,38 @@ class ModuleInterface {
313313
#endif
314314
default: return false; // Unrecognized message
315315
}
316+
#ifdef DEBUG_PRINT
317+
if (message[0] == mcSendSettings) { // Can be called for master, and for module if it has own GUI
318+
dname(); Serial.print(F("Send Settings: "));
319+
settings.debug_print_values();
320+
} else
321+
#ifdef IS_MASTER
322+
if (message[0] == mcSendInputs) {
323+
dname(); Serial.print(F("Send Inputs: "));
324+
inputs.debug_print_values();
325+
}
326+
#else
327+
if (message[0] == mcSendSettingContract) {
328+
dname(); Serial.print(F("Send Settings contract: "));
329+
settings.debug_print_contract();
330+
} else
331+
if (message[0] == mcSendInputContract) {
332+
dname(); Serial.print(F("Send Inputs contract: "));
333+
inputs.debug_print_contract();
334+
} else
335+
if (message[0] == mcSendOutputContract) {
336+
dname(); Serial.print(F("Send Outputs contract: "));
337+
outputs.debug_print_contract();
338+
} else
339+
if (message[0] == mcSendOutputs) {
340+
dname(); Serial.print(F("Send Outputs: "));
341+
outputs.debug_print_values();
342+
} else
343+
if (message[0] == mcSendStatus) {
344+
dname(); Serial.print(F("Send Status: ")); Serial.println(message[1]);
345+
}
346+
#endif
347+
#endif
316348
return true;
317349
}
318350

ModuleInterfacePersistence.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ bool write_settings_to_eeprom(const ModuleInterface &mi, uint16_t eeprom_start_p
6464

6565
bool write_to_eeprom_when_needed(ModuleInterface &mi, uint32_t &last_save, uint32_t save_interval_ms = 600000, uint16_t eeprom_start_pos = 0) {
6666
// Only save settings when actually changed and not too often (do not wear out EEPROM memory)
67-
if (millis() - last_save >= save_interval_ms) {
67+
if ((uint32_t)(millis() - last_save) >= save_interval_ms) {
6868
last_save = millis();
6969
return write_settings_to_eeprom(mi, eeprom_start_pos);
7070
}

ModuleVariableSet.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,14 @@ struct ModuleVariableSet {
7070
bool preallocate_variables(const uint8_t variable_count) {
7171
num_variables = variable_count;
7272
if (variables) { delete[] variables; variables = NULL; }
73-
if (num_variables == 0) return true;
73+
if (num_variables == 0) { contract_id = calculate_contract_id(); return true; }
7474
variables = new ModuleVariable[num_variables];
7575
if (!variables) { out_of_memory = true; return false; }
7676
return true;
7777
}
7878

7979
void set_variables(const char *names_and_types) { // Textual format like "var1:u1 var2:f" specified in worker
80-
// Parse string, count number of variables
80+
// Parse string, count number of variables
8181
if (names_and_types) {
8282
const char *p = names_and_types;
8383
uint8_t nvar = 0;
@@ -427,7 +427,6 @@ struct ModuleVariableSet {
427427
requested_time = 0;
428428
#endif
429429

430-
#ifdef DEBUG_PRINT
431430
void debug_print_contract() const {
432431
if (num_variables == 0) Serial.print(F("Empty contract."));
433432
else for (uint8_t i = 0; i < num_variables; i++) {
@@ -436,7 +435,7 @@ struct ModuleVariableSet {
436435
}
437436
Serial.println("");
438437
}
439-
438+
440439
void debug_print_values() const {
441440
if (num_variables == 0) Serial.print(F("Empty contract."));
442441
else for (uint8_t i = 0; i < num_variables; i++) {
@@ -456,6 +455,5 @@ struct ModuleVariableSet {
456455
}
457456
Serial.println("");
458457
}
459-
#endif
460458
};
461459

PJONEthernetTunnelerLink.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* This PJONEthernetTunnelerLink class transfers PJON packets over TCP/IP Ethernet connections,
2+
assuming a PJONEthernetTunneler device receives the Ethernet packages and sends them ahead on a
3+
PJON bus to the target device.
4+
*/
5+
6+
#pragma once
7+
8+
#include <PJONLink.h>
9+
//#include <EthernetLink.h>
10+
11+
class PJONEthernetTunnelerLink : public Link {
12+
static void link_receiver_callback(uint8_t id, const uint8_t *payload, uint16_t length, void *callback_object) {
13+
if (callback_object && ((PJONEthernetTunnelerLink*)callback_object)->_receiver)
14+
((PJONEthernetTunnelerLink*)callback_object)->_receiver((uint8_t*)payload, length, ((PJONEthernetTunnelerLink*)callback_object)->lpi);
15+
}
16+
receiver _receiver = NULL;
17+
public:
18+
EthernetLink link;
19+
PacketInfo lpi;
20+
long dummy_bus_id = 0;
21+
22+
PJONEthernetTunnelerLink() { link.set_receiver(link_receiver_callback, this); };
23+
PJONEthernetTunnelerLink(uint8_t id) { link. set_id(id); link.set_receiver(link_receiver_callback, this); };
24+
25+
//**************** Overridden functions below *******************
26+
27+
uint16_t receive() { return link.receive(); }
28+
uint16_t receive(uint32_t duration) { return link.receive(duration); }
29+
30+
uint8_t update() { link.update(); return 0; }
31+
32+
uint16_t send_packet(uint8_t id, const uint8_t *b_id, const char *string, uint16_t length, uint32_t duration, uint16_t header) {
33+
// Create a PacketInfo struct, then serialize it along with the message
34+
memset(&lpi, 0, sizeof lpi);
35+
// TODO: Use extended header and correct MI bit according to PJON standard
36+
lpi.header = header==0 ? SENDER_INFO_BIT | ACK_REQUEST_BIT | MI_PJON_BIT : header; //MI_EXTENDED_HEADER_BIT;
37+
// lpi.extended_header = MI_PJON_BIT;
38+
lpi.receiver_id = id;
39+
copy_bus_id(lpi.receiver_bus_id, b_id);
40+
lpi.sender_id = get_id();
41+
copy_bus_id(lpi.sender_bus_id, (uint8_t*) &dummy_bus_id);
42+
43+
// Now concatenate and send
44+
char buf[length + sizeof lpi];
45+
memcpy(buf, &lpi, sizeof lpi);
46+
memcpy(&buf[sizeof lpi], string, length);
47+
return link.send_with_duration(id, buf, sizeof lpi + length, 1000000);
48+
}
49+
50+
const PacketInfo &get_last_packet_info() const { return lpi; }
51+
uint16_t get_header() const { return lpi.header; }
52+
53+
uint8_t get_id() const { return link.get_id(); }
54+
const uint8_t *get_bus_id() const { return (const uint8_t*) &dummy_bus_id; }
55+
56+
void set_receiver(receiver r) { _receiver = r; }
57+
// TODO: PJONLink should accept link_receiver, and take the responsibility for handling PJON receiver and forwarding the call
58+
59+
};
60+

PJONLink.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ struct PJONLink : public Link {
2222
: send_packet_blocking(id, b_id, (char *)string, length, header, timeout, false);
2323
}
2424

25-
const PacketInfo &get_last_packet_info() const { return bus.last_packet_info; }
26-
uint16_t get_header() const { return bus.get_header(); }
25+
const PJON_Packet_Info &get_last_packet_info() const { return bus.last_packet_info; }
26+
uint16_t get_header() const { return bus.config; }
2727
uint8_t get_id() const { return bus.device_id(); }
2828
const uint8_t *get_bus_id() const { return bus.bus_id; }
29-
void set_receiver(receiver r) { bus.set_receiver(r); }
29+
void set_receiver(PJON_Receiver r) { bus.set_receiver(r); }
3030

3131
protected:
3232
// This function will block until packet has been delivered or timeout occurs.
@@ -36,7 +36,7 @@ struct PJONLink : public Link {
3636
const uint8_t *b_id,
3737
const char *string,
3838
uint16_t length,
39-
uint16_t header = NOT_ASSIGNED,
39+
uint16_t header = PJON_NOT_ASSIGNED,
4040
uint32_t timeout = 3000000,
4141
bool do_receive = false
4242
) {
@@ -47,21 +47,21 @@ struct PJONLink : public Link {
4747
string,
4848
length,
4949
header
50-
))) return FAIL;
51-
uint16_t state = FAIL;
50+
))) return PJON_FAIL;
51+
uint16_t state = PJON_FAIL;
5252
uint32_t attempts = 0;
5353
uint32_t time = micros(), start = time;
54-
while(state != ACK && attempts <= MAX_ATTEMPTS && (uint32_t)(micros() - start) <= timeout) {
54+
while(state != PJON_ACK && attempts <= bus.strategy.get_max_attempts() && (uint32_t)(micros() - start) <= timeout) {
5555
state = bus.send_packet((char*)bus.data, length);
56-
if(state == ACK) return state;
56+
if(state == PJON_ACK) return state;
5757
attempts++;
5858
if (do_receive) {
59-
uint32_t delay = (attempts * attempts * attempts);
60-
if (state != FAIL) delay += (uint32_t) (random(0, COLLISION_DELAY));
59+
uint32_t delay = bus.strategy.back_off(attempts);
60+
if (state != PJON_FAIL) bus.strategy.handle_collision();
6161
while((uint32_t)(micros() - time) < delay) bus.receive();
6262
} else {
63-
if(state != FAIL) delayMicroseconds(random(0, COLLISION_DELAY));
64-
while((uint32_t)(micros() - time) < (attempts * attempts * attempts));
63+
if(state != PJON_FAIL) bus.strategy.handle_collision();
64+
while((uint32_t)(micros() - time) < bus.strategy.back_off(attempts));
6565
}
6666
time = micros();
6767
}

0 commit comments

Comments
 (0)