- Why does startKIT and eXplorerKIT have different number of timers in this code?
- The question really is why is the startKIT is listed with one more timer than the code shows? DEBUG_PRINT_TEST makes no difference
- Also, number of chanends starts at 4 and increments by 3 per new client. Why doesn't it start with 3 chanends? DEBUG_PRINT_TEST makes no difference here either
- Some of this has been discussed before here at XCore Exchange, at Calculating number of chanends
- With DO_PLACED == 1 the code breaks completely down. I have filed this as an XMOS Ticket
- Aside: I am showing this and other examples at Client-server and call-based notification, placement and chanend numbers (disclaimer: no money, ads, gifts with my notes (just fun and expenses!))
Code: Select all
#include <platform.h> // core
#include <stdio.h>
#include <timer.h> // delay_milliseconds(200), XS1_TIMER_HZ etc
#define DEBUG_PRINT_TEST 1
#define debug_print(fmt, ...) do { if(DEBUG_PRINT_TEST) printf(fmt, __VA_ARGS__); } while (0)
typedef enum {false,true} bool;
typedef signed int time32_t;
typedef unsigned data_t;
typedef interface notify_if_t {
[[guarded]]
void start_collect_data (void);
[[notification]]
slave void data_ready (void);
[[clears_notification]]
data_t get_data (void);
} notify_if_t;
#define NUM_CLIENTS 7 // DO_PLACED 0: MAX 7. 1 timer and 3 chanends per client
[[combinable]]
void server_task (server notify_if_t i_notify[NUM_CLIENTS]) {
timer tmr;
time32_t time;
bool collectData = false;
bool session = false; // Necessary!
data_t data = 0;
int session_index_of_client;
debug_print ("%s\n", "server_task");
tmr :> time; // immediately
while (1) {
select {
case (session == false) => i_notify[int index_of_client].start_collect_data (void) : {
collectData = true;
session = true;
debug_print ("%d started\n", index_of_client);
session_index_of_client = index_of_client;
tmr :> time; // immediately
} break;
case (collectData == true) => tmr when timerafter (time) :> void : {
collectData = false;
data++; // This is supposed to take a while, that's why we used notification: to get it decoupled
debug_print ("%d produced %u\n", session_index_of_client, data);
i_notify[session_index_of_client].data_ready();
} break;
case i_notify[int index_of_client].get_data (void) -> data_t return_Data : {
debug_print ("%d sent %u\n", index_of_client, data);
session = false;
return_Data = data;
} break;
}
}
}
[[combinable]]
void client_task (client notify_if_t i_notify, const int index_of_client) {
timer tmr;
time32_t time;
bool expect_notification = false;
unsigned cnt = 0;
debug_print ("client_task %d\n", index_of_client);
tmr :> time; // immediately
while (1) {
select {
case (expect_notification == false) => tmr when timerafter (time) :> void : {
debug_print ("\n%d START\n", index_of_client);
i_notify.start_collect_data();
expect_notification = true;
} break;
case (expect_notification == true) => i_notify.data_ready() : {
data_t data = i_notify.get_data();
cnt++;
debug_print ("%d GOT %u is #%u\n", index_of_client, data, cnt);
expect_notification = false;
time += XS1_TIMER_HZ; // 1 second
} break;
}
}
}
int main() {
#define DO_PLACED 0 // 1 simply does not work!
notify_if_t if_notify[NUM_CLIENTS];
#if (DO_PLACED == 0)
/*
STARTKIT:
NUM_CLIENTS 1 Cores 2 Timers 3 Chanends 4 OKAY.
NUM_CLIENTS 2 Cores 3 Timers 4 Chanends 7 OKAY.
NUM_CLIENTS 3 Cores 4 Timers 5 Chanends 10 OKAY.
NUM_CLIENTS 4 Cores 5 Timers 6 Chanends 13 OKAY.
NUM_CLIENTS 5 Cores 6 Timers 7 Chanends 16 OKAY.
NUM_CLIENTS 6 Cores 7 Timers 8 Chanends 19 OKAY.
NUM_CLIENTS 7 Cores 8 Timers 9 Chanends 22 OKAY.
XCORE-200-EXPLORER has one less timer (xTIMEcomposer 14.3.3):
NUM_CLIENTS 1 Cores 2 Timers 2 Chanends 4 OKAY.
NUM_CLIENTS 2 Cores 3 Timers 3 Chanends 7 OKAY.
NUM_CLIENTS 3 Cores 4 Timers 4 Chanends 10 OKAY.
NUM_CLIENTS 4 Cores 5 Timers 5 Chanends 13 OKAY.
NUM_CLIENTS 5 Cores 6 Timers 6 Chanends 16 OKAY.
NUM_CLIENTS 6 Cores 7 Timers 7 Chanends 19 OKAY.
NUM_CLIENTS 7 Cores 8 Timers 8 Chanends 22 OKAY.
*/
par {
server_task(if_notify);
par (size_t i = 0; i < NUM_CLIENTS; i++) {
client_task (if_notify[i], i);
}
}
#elif (DO_PLACED == 1)
/*
NUM_CLIENTS 1 Cores 1 Timers 2 Chanends 2 OKAY. Constraints checks PASSED. BUT DOES NOT RUN!
NUM_CLIENTS 2 Cores 1+ Timers 2+ Chanends 3+ MAYBE. PASSED WITH CAVEATS. DOES NOT RUN
NUM_CLIENTS 3 Cores 1+ Timers 2+ Chanends 4+ MAYBE. PASSED WITH CAVEATS. DOES NOT RUN
Constraint check for tile[0]:
Cores available: 8, used: 1+. MAYBE
Timers available: 10, used: 2+. MAYBE
Chanends available: 32, used: 4+. MAYBE
Memory available: 65536, used: 12460+. MAYBE
(Stack: 1112+, Code: 10380, Data: 968)
Constraints checks PASSED WITH CAVEATS.
*/
par {
on tile[0].core[0]: server_task(if_notify);
par (size_t i = 0; i < NUM_CLIENTS; i++) {
on tile[0].core[0]: client_task (if_notify[i], i);
}
}
#endif
return 0;