main.cpp 27 KB
Newer Older
philip's avatar
philip committed
1
2
#include "config.h"

philip's avatar
philip committed
3
#include "stm32h7xx_ll_utils.h"
philip's avatar
philip committed
4
5
6

#include "AggregatMotor.h"

philip's avatar
philip committed
7
8
9
10
11
12
#include "midimessage/midimessage.h"
#include "midimessage/simpleparser.h"
#include "midimessage/packers.h"


#if USE_USBMIDI
philip's avatar
philip committed
13
14
15
#include "UsbMidiAggregat.h"
#endif

philip's avatar
philip committed
16
17

#if USE_NETMIDI
philip's avatar
philip committed
18
// low level interfaces needed to solve platform bug
philip's avatar
philip committed
19
20
21
#include "stm32h743xx.h"
#include "stm32xx_emac.h"

philip's avatar
philip committed
22
#include "EthernetInterface.h"
philip's avatar
philip committed
23
24
// #include "LWIPStack.h"
#include "nsapi_types.h"
philip's avatar
philip committed
25

philip's avatar
philip committed
26
// mdns responder
philip's avatar
philip committed
27
#include "minimr.h"
philip's avatar
philip committed
28
29
#endif //USE_NETMIDI

philip's avatar
philip committed
30
31


philip's avatar
philip committed
32

philip's avatar
philip committed
33
34
35
36
37
38
39
40
41
42
/************ TYPES ************/

typedef enum {
    SourceUsb,
    SourceMidi,
    SourceNet
} Source;

/************ SIGNATURES ************/

philip's avatar
philip committed
43
void core_init();
philip's avatar
philip committed
44

philip's avatar
philip committed
45
46
void gpio_init();

philip's avatar
philip committed
47
48
49
void motors_init();
void motors_suspend();
void motors_resume();
philip's avatar
..    
philip committed
50
void motors_run();
philip's avatar
philip committed
51

philip's avatar
philip committed
52
53
void motors_center();

philip's avatar
philip committed
54
// void controller_init();
philip's avatar
philip committed
55
56
57
58
void controller_handle_msg(uint8_t * buffer, size_t length, Source source);

#if USE_USBMIDI == 1
void usbmidi_init();
philip's avatar
philip committed
59
void usbmidi_run();
philip's avatar
philip committed
60
void usbmidi_tx(uint8_t * buffer, size_t length);
philip's avatar
philip committed
61

philip's avatar
philip committed
62
63
// void usbmidi_event_callback();
void usbmidi_rx(uint8_t * buffer, uint8_t length, void * context); // parser callback handler
philip's avatar
philip committed
64

philip's avatar
philip committed
65
66
#else //USE_USBMIDI == 0
#define usbmidi_init()
philip's avatar
philip committed
67
#define usbmidi_run()
philip's avatar
philip committed
68
69
70
#define usbmidi_tx()
#endif //USE_USBMIDI

philip's avatar
philip committed
71
72


philip's avatar
philip committed
73
74
75
76
#if USE_MIDI == 1
void midi_init();
void midi_run();
void midi_tx(uint8_t * buffer, size_t length);
philip's avatar
philip committed
77

philip's avatar
philip committed
78
79
80
81
82
83
84
void midi_rx(uint8_t * buffer, uint8_t length, void * context); // parser callback handler
#else //USE_MIDI == 0
#define midi_init()
#define midi_tx(buffer, length)
#define midi_run()
#endif //USE_MIDI

philip's avatar
philip committed
85
86


philip's avatar
philip committed
87
88
#if USE_NETMIDI == 1
void netmidi_init();
philip's avatar
philip committed
89
void netmidi_run();
philip's avatar
philip committed
90
void netmidi_tx(uint8_t * buffer, size_t length);
philip's avatar
philip committed
91
92
93

void eth_status_changed(nsapi_event_t evt, intptr_t intptr);
void eth_ifup();
philip's avatar
philip committed
94

philip's avatar
philip committed
95
96
void mdns_init();
void mdns_deinit();
philip's avatar
philip committed
97
int mdns_rr_callback(enum minimr_dns_rr_fun_type type, struct minimr_dns_rr * rr, ...);
philip's avatar
philip committed
98
99
#else //USE_NETMIDI == 0
#define netmidi_init()
philip's avatar
philip committed
100
#define netmidi_run()
philip's avatar
philip committed
101
102
103
#define netmidi_tx(buffer, length)
#endif //USE_NETMIDI

philip's avatar
philip committed
104
105
106



philip's avatar
philip committed
107
108
/************ LOCAL VARIABLES ************/

philip's avatar
philip committed
109
uint32_t hw_device_id = 0;
philip's avatar
philip committed
110

philip's avatar
philip committed
111
112
volatile bool btn_plus_1_request = false;
volatile bool btn_plus_2_request = false;
philip's avatar
..    
philip committed
113

philip's avatar
philip committed
114
volatile bool motors_running = false;
philip's avatar
philip committed
115
volatile bool motors_center_request = false;
philip's avatar
..    
philip committed
116

philip's avatar
philip committed
117
AggregatMotor motors[MOTOR_COUNT] = {
philip's avatar
..    
philip committed
118
119
  #if MOTOR_COUNT > 0
  AggregatMotor(MOTOR_1_PWR_PIN, MOTOR_1_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
philip's avatar
philip committed
120
121
  #endif
  #if MOTOR_COUNT > 1
philip's avatar
..    
philip committed
122
  AggregatMotor(MOTOR_2_PWR_PIN, MOTOR_2_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
philip's avatar
philip committed
123
124
  #endif
  #if MOTOR_COUNT > 2
philip's avatar
..    
philip committed
125
  AggregatMotor(MOTOR_3_PWR_PIN, MOTOR_3_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
philip's avatar
philip committed
126
127
  #endif
  #if MOTOR_COUNT > 3
philip's avatar
..    
philip committed
128
  AggregatMotor(MOTOR_4_PWR_PIN, MOTOR_4_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
philip's avatar
philip committed
129
130
  #endif
  #if MOTOR_COUNT > 4
philip's avatar
..    
philip committed
131
  AggregatMotor(MOTOR_5_PWR_PIN, MOTOR_5_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
philip's avatar
philip committed
132
133
  #endif
  #if MOTOR_COUNT > 5
philip's avatar
..    
philip committed
134
  AggregatMotor(MOTOR_6_PWR_PIN, MOTOR_6_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
philip's avatar
philip committed
135
136
  #endif
  #if MOTOR_COUNT > 6
philip's avatar
..    
philip committed
137
  AggregatMotor(MOTOR_7_PWR_PIN, MOTOR_7_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
philip's avatar
philip committed
138
139
  #endif
  #if MOTOR_COUNT > 7
philip's avatar
..    
philip committed
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  AggregatMotor(MOTOR_8_PWR_PIN, MOTOR_8_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
  #endif
  #if MOTOR_COUNT > 8
  AggregatMotor(MOTOR_9_PWR_PIN, MOTOR_9_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
  #endif
  #if MOTOR_COUNT > 9
  AggregatMotor(MOTOR_10_PWR_PIN, MOTOR_10_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
  #endif
  #if MOTOR_COUNT > 10
  AggregatMotor(MOTOR_11_PWR_PIN, MOTOR_11_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
  #endif
  #if MOTOR_COUNT > 11
  AggregatMotor(MOTOR_12_PWR_PIN, MOTOR_12_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
  #endif
  #if MOTOR_COUNT > 12
  AggregatMotor(MOTOR_13_PWR_PIN, MOTOR_13_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
  #endif
  #if MOTOR_COUNT > 13
  AggregatMotor(MOTOR_14_PWR_PIN, MOTOR_14_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
  #endif
  #if MOTOR_COUNT > 14
  AggregatMotor(MOTOR_15_PWR_PIN, MOTOR_15_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
  #endif
  #if MOTOR_COUNT > 15
  AggregatMotor(MOTOR_16_PWR_PIN, MOTOR_16_PWM_PIN, MOTOR_REFRESH_RATE_HZ, MOTOR_PULSEWIDTH_MIN_USEC, MOTOR_PULSEWIDTH_MAX_USEC),
philip's avatar
philip committed
165
  #endif
philip's avatar
philip committed
166
167
};

philip's avatar
..    
philip committed
168

philip's avatar
philip committed
169
#if USE_CHANNEL_SELECT 
philip's avatar
philip committed
170
BusIn channel_select_bus(CHANNEL_SELECT_PIN_1, CHANNEL_SELECT_PIN_2, CHANNEL_SELECT_PIN_3, CHANNEL_SELECT_PIN_4);
philip's avatar
philip committed
171
172
#define get_channel() channel_select_bus.read()
#else
philip's avatar
philip committed
173
#define get_channel() CHANNEL_SELECT_DEFAULT
philip's avatar
philip committed
174
175
176
177
178
179
180
181
#endif //USE_CHANNEL_SELECT

#if USE_DEVICE_ID_SELECT
BusIn device_id_bus(DEVICE_ID_SELECT_PIN_1, DEVICE_ID_SELECT_PIN_2, DEVICE_ID_SELECT_PIN_3, DEVICE_ID_SELECT_PIN_4);
#define get_device_id()     device_id_bus.read()
#else
#define get_device_id()     DEVICE_ID_SELECT_DEFAULT
#endif //USE_ID_SELECT
philip's avatar
philip committed
182

philip's avatar
philip committed
183
184
185
186
#if USE_CFG
DigitalIn cfg1(CFG_RSRV_1_PIN);
DigitalIn cfg2(CFG_RSRV_2_PIN);
#endif //USE_CFG
philip's avatar
test    
philip committed
187

philip's avatar
philip committed
188
189
190
191
#if USE_BUTTONS
InterruptIn btn_center(BTN_CENTER_PIN);
InterruptIn btn_plus1(BTN_PLUS_1_PIN);
InterruptIn btn_plus2(BTN_PLUS_2_PIN);
philip's avatar
..    
philip committed
192

philip's avatar
philip committed
193
194
195
196
volatile bool btn_plus1_touched = false;
volatile bool btn_plus2_touched = false;
#endif

philip's avatar
philip committed
197
198
199
200
201
202
#if USE_STATUS_LEDS
DigitalOut led_pwr(LED_PWR_PIN, 1);
DigitalOut led_motors(LED_MTR_PIN, 0);
#endif


philip's avatar
philip committed
203
204

#if USE_USBMIDI
philip's avatar
philip committed
205
UsbMidiAggregat usbmidi(USB_POWER_PIN, false);
philip's avatar
philip committed
206
MidiMessage::SimpleParser_t usbmidi_parser;
philip's avatar
philip committed
207
208
209
210
211
#endif //USE_USBMIDI

#if USE_USBMIDI && USE_FORWARDING_CONTROLS
DigitalIn usb_to_midi_pin(USB_TO_MIDI_PIN);
DigitalIn usb_to_net_pin(USB_TO_NET_PIN);
philip's avatar
..    
philip committed
212

philip's avatar
philip committed
213
214
215
216
217
#define usb_to_midi()   usb_to_midi_pin.read()
#define usb_to_net()    usb_to_net_pin.read()
#else
#define usb_to_midi()   USB_TO_MIDI_DEFAULT    
#define usb_to_net()    USB_TO_NET_DEFAULT
philip's avatar
philip committed
218
#endif //USE_USBMIDI && USE_FORWARDING_CONTROLS
philip's avatar
..    
philip committed
219

philip's avatar
philip committed
220
221
222
223
224
#if USE_USBMIDI && USE_STATUS_LEDS
DigitalOut usb_led1(LED_USB_1_PIN);
DigitalOut usb_led2(LED_USB_2_PIN);
#endif

philip's avatar
..    
philip committed
225

philip's avatar
philip committed
226

philip's avatar
philip committed
227
#if USE_MIDI
philip's avatar
philip committed
228
229
230
BufferedSerial midi(MIDI_TX_PIN, MIDI_RX_PIN);

MidiMessage::SimpleParser_t midi_parser;
philip's avatar
philip committed
231
#endif //USE_USBMIDI
philip's avatar
philip committed
232

philip's avatar
philip committed
233
234
235
#if USE_MIDI && USE_FORWARDING_CONTROLS
DigitalIn midi_to_usb_pin(MIDI_TO_USB_PIN);
DigitalIn midi_to_net_pin(MIDI_TO_NET_PIN);
philip's avatar
philip committed
236
237
238
239
240
#define midi_to_usb()   midi_to_usb_pin.read()
#define midi_to_net()   midi_to_net_pin.read()
#else
#define midi_to_usb()   MIDI_TO_USB_DEFAULT
#define midi_to_net()   MIDI_TO_NET_DEFAULT
philip's avatar
philip committed
241
#endif // USE_MIDI && USE_FORWARDING_CONTROLS
philip's avatar
philip committed
242

philip's avatar
philip committed
243
244
245
246
#if USE_MIDI && USE_STATUS_LEDS
DigitalOut midi_led1(LED_MIDI_1_PIN);
DigitalOut midi_led2(LED_MIDI_2_PIN);
#endif
philip's avatar
philip committed
247

philip's avatar
philip committed
248
249

#if USE_NETMIDI 
philip's avatar
philip committed
250
EthernetInterface eth;
philip's avatar
philip committed
251
252
Thread net_thread;
SocketAddress ip;
philip's avatar
philip committed
253
UDPSocket udp_sock;
philip's avatar
philip committed
254

philip's avatar
test    
philip committed
255
bool eth_reconnect = false; 
philip's avatar
philip committed
256

philip's avatar
philip committed
257
// DigitalOut net_led(LED_NET_1_PIN);
philip's avatar
philip committed
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274

minimr_dns_rr_a RR_A = {
    .type = MINIMR_DNS_TYPE_A,
    .cache_class = MINIMR_DNS_CACHEFLUSH | MINIMR_DNS_CLASS_IN,
    .ttl = 120,
    .fun = mdns_rr_callback
};
minimr_dns_rr_aaaa RR_AAAA = {
    .type = MINIMR_DNS_TYPE_AAAA,
    .cache_class = MINIMR_DNS_CACHEFLUSH | MINIMR_DNS_CLASS_IN,
    .ttl = 120,
    .fun = mdns_rr_callback
};
struct minimr_dns_rr * mdns_records[MDNS_RR_COUNT];
SocketAddress mdns_addr;

UDPSocket mdns_sock;
philip's avatar
philip committed
275
276
#endif

philip's avatar
philip committed
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#if USE_NETMIDI && USE_FORWARDING_CONTROLS
DigitalIn net_to_usb_pin(NET_TO_USB_PIN);
DigitalIn net_to_midi_pin(NET_TO_MIDI_PIN);

#define net_to_usb()    net_to_usb_pin.read()
#define net_to_midi()   net_to_midi_pin.read()
#else
#define net_to_usb()    NET_TO_USB_DEFAULT
#define net_to_midi()   NET_TO_MIDI_DEFAULT
#endif // USE_NETMIDI && USE_FORWARDING_CONTROLS

#if USE_NETMIDI && USE_STATUS_LEDS
DigitalOut net_led1(LED_NET_1_PIN);
DigitalOut net_led2(LED_NET_2_PIN);
#endif

philip's avatar
philip committed
293
294
295



philip's avatar
philip committed
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/************ INLINE FUNCTIONS ************/

inline float u7_to_pos(uint8_t value)
{
    return ((float)value) / 128.0;
}

inline float u14_to_pos(uint16_t value)
{
    return ((float)value) / 16383.0;
}

inline float s14_to_pos(int value)
{
    return u14_to_pos(value + 8192);
}

philip's avatar
philip committed
313
314
315

void do_nothing(){}

philip's avatar
philip committed
316
317
318



philip's avatar
philip committed
319
320
/************ FUNCTIONS ************/

philip's avatar
philip committed
321
void core_init()
philip's avatar
philip committed
322
{
philip's avatar
philip committed
323
    hw_device_id = LL_GetUID_Word0() ^ LL_GetUID_Word1() ^ LL_GetUID_Word2();
philip's avatar
philip committed
324

philip's avatar
philip committed
325
    srand(hw_device_id + time(NULL));
philip's avatar
philip committed
326
327
}

philip's avatar
philip committed
328
329
void gpio_init()
{
philip's avatar
philip committed
330
331
332
333
334

    #if USE_DEVICE_ID_SELECT
    // device_id_bus.mode(PullNone);
    #endif

philip's avatar
philip committed
335
    #if USE_CHANNEL_SELECT
philip's avatar
philip committed
336
    // channel_select_bus.mode(PullNone);
philip's avatar
philip committed
337
    #endif
philip's avatar
philip committed
338

philip's avatar
philip committed
339
340
    #if USE_BUTTONS
    btn_center.rise([](){
philip's avatar
philip committed
341
        motors_center_request = true;
philip's avatar
philip committed
342
343
        // usb_led1 = !usb_led1;
        // usb_led2 = !usb_led2;
philip's avatar
philip committed
344
345
    });
    btn_plus1.rise([](){
philip's avatar
philip committed
346
        btn_plus1_touched = true;
philip's avatar
philip committed
347
348
        // midi_led1 = !midi_led1;
        // midi_led2 = !midi_led2;
philip's avatar
philip committed
349
350
    });
    btn_plus2.rise([](){
philip's avatar
philip committed
351
        btn_plus2_touched = true;
philip's avatar
philip committed
352
353
        // net_led1 = !net_led1;
        // net_led2 = !net_led2;
philip's avatar
philip committed
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
    });
    #endif //USE_BUTTONS

    printf("device_id %d\n", get_device_id());
    printf("channel %d\n", get_channel());

    printf("usb -> midi %d\n", usb_to_midi());
    printf("usb -> net %d\n", usb_to_net());
    printf("midi -> usb %d\n", midi_to_usb());
    printf("midi -> net %d\n", midi_to_net());
    printf("net -> usb %d\n", net_to_usb());
    printf("net -> midi %d\n", net_to_midi());

    #if USE_CFG
    printf("cfg1 %d\n", cfg1.read());
    printf("cfg2 %d\n", cfg2.read());
philip's avatar
philip committed
370
    #endif
philip's avatar
philip committed
371
372
}

philip's avatar
philip committed
373
374
375
376
377
void motors_init()
{
    for(int i = 0; i < MOTOR_COUNT; i++){

        // init to center position
philip's avatar
..    
philip committed
378
        // motors[i] = 0.5;
philip's avatar
philip committed
379

philip's avatar
..    
philip committed
380
        // start suspended (well, they are initialized in suspended mode)
philip's avatar
philip committed
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
        motors[i].suspend();
    }
}

void motors_suspend()
{
    for(int i = 0; i < MOTOR_COUNT; i++){
        motors[i].suspend();
    }

    motors_running = false;
}

void motors_resume()
{
    for(int i = 0; i < MOTOR_COUNT; i++){
        motors[i].resume();
    }
    motors_running = true;
}

philip's avatar
..    
philip committed
402
void motors_run()
philip's avatar
philip committed
403
{
philip's avatar
philip committed
404
405
406
407
408
    if (motors_center_request){
        motors_center();
        motors_center_request = false;
    }

philip's avatar
philip committed
409
410
    bool is_off = !motors_running;

philip's avatar
..    
philip committed
411
412
    for(int i = 0; i < MOTOR_COUNT; i++){
        motors[i].run();
philip's avatar
philip committed
413

philip's avatar
philip committed
414
        // is_off |= !motors[i].get_state();
philip's avatar
..    
philip committed
415
    }
philip's avatar
philip committed
416
417

    led_motors = is_off;
philip's avatar
philip committed
418
419
}

philip's avatar
philip committed
420
421
422
423
424
425
426
void motors_center()
{
    for(int i = 0; i < MOTOR_COUNT; i++){
        motors[i] = 0.5;
    }
}

philip's avatar
..    
philip committed
427

philip's avatar
philip committed
428
429
void controller_handle_msg(uint8_t * buffer, size_t length, Source source)
{
philip's avatar
philip committed
430
431
432
433
434
    // printf("CMD (len %d) ", length);
    // for(int i = 0; i < length; i++){
    //     printf("%02x", buffer[i]);
    // }
    // printf("\n");
philip's avatar
philip committed
435

436

philip's avatar
..    
philip committed
437
438
    #if USE_CONTROLLER_LOGIC == 1

philip's avatar
philip committed
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
    MIDIMessage msg;

    msg.from_raw(buffer, length);

    if (msg.length == 1){   // system real time messages

        // 0xFA = start, 0xFB = continue
        if (msg.data[0] == 0xFA || msg.data[0] == 0xFB){
            motors_resume();
        }

        // 0xFC = stop
        if (msg.data[0] == 0xFC){
            motors_suspend();
        }

philip's avatar
..    
philip committed
455
        #if USE_SYSTEM_RESET == 1
philip's avatar
philip committed
456
457
458
        // 0xFF = reset
        if (msg.data[0] == 0xFF){
            system_reset();
philip's avatar
philip committed
459
            printf("system_reset??\n");
philip's avatar
philip committed
460
        }
philip's avatar
philip committed
461
        #else
philip's avatar
..    
philip committed
462
        printf("USE_SYSTEM_RESET == 0\n");
philip's avatar
philip committed
463
464
465
466
        #endif
    }


philip's avatar
..    
philip committed
467
    // position control
philip's avatar
philip committed
468
    if (msg.type() == MIDIMessage::ControlChangeType){
philip's avatar
philip committed
469
        if (msg.channel() == get_channel()){
philip's avatar
philip committed
470
            int32_t motori = msg.controller() - CC_CONTROLLER_OFFSET;
philip's avatar
philip committed
471
472
473

            if (0 <= motori && motori < MOTOR_COUNT){
                float pos = u7_to_pos(msg.value());
philip's avatar
philip committed
474
                // printf("motor[%d] = %d\n", motori, (int)(pos*100));
philip's avatar
philip committed
475
476
477
478
479
                motors[motori] = pos;
            }
        }
    }

philip's avatar
..    
philip committed
480
    #if USE_PITCHBEND_CONTROL
philip's avatar
philip committed
481
    // each channel controls a motor starting from channel_offset
philip's avatar
?    
philip committed
482
483
    if (msg.type() == MIDIMessage::PitchWheelType){
        int32_t motori = msg.channel();
philip's avatar
philip committed
484
        
philip's avatar
?    
philip committed
485
486
487
488
        if (0 <= motori && motori < MOTOR_COUNT){
            float pos = s14_to_pos(msg.pitch());
            motors[motori] = pos;
        }
philip's avatar
philip committed
489
        
philip's avatar
?    
philip committed
490
    }
philip's avatar
..    
philip committed
491
    #endif //USE_PITCHBEND_CONTROL
philip's avatar
philip committed
492

philip's avatar
..    
philip committed
493
494
495
    // power control
    if (msg.type() == MIDIMessage::NoteOnType || msg.type() == MIDIMessage::NoteOffType){
        if (msg.channel() == get_channel()){
philip's avatar
philip committed
496
            int32_t motori = msg.key();
philip's avatar
..    
philip committed
497
498
499

            if (0 <= motori && motori < MOTOR_COUNT){
                // turn on or off
philip's avatar
philip committed
500
                bool off = msg.type() == MIDIMessage::NoteOffType || msg.velocity() == 0;
philip's avatar
philip committed
501
                // printf("motor pwr %d := %d\n", motori, !off);
philip's avatar
philip committed
502
                motors[motori] = !off;
philip's avatar
..    
philip committed
503
504
505
506
507
508
            }
        }
    }


    #endif //USE_CONTROLLER_LOGIC == 1
509

philip's avatar
philip committed
510
    #if USE_USBMIDI
philip's avatar
philip committed
511
    if (source == SourceUsb){
philip's avatar
philip committed
512
        if (usb_to_midi()){
philip's avatar
philip committed
513
514
            midi_tx(buffer, length);
        }
philip's avatar
philip committed
515
        if (usb_to_net()){
philip's avatar
philip committed
516
517
518
            netmidi_tx(buffer, length);
        }
    }
philip's avatar
philip committed
519
520
    #endif
    #if USE_MIDI
philip's avatar
philip committed
521
    if (source == SourceMidi){
philip's avatar
philip committed
522
        if (midi_to_usb()){
philip's avatar
philip committed
523
524
            usbmidi_tx(buffer, length);
        }
philip's avatar
philip committed
525
        if (midi_to_net()){
philip's avatar
philip committed
526
527
528
            netmidi_tx(buffer, length);
        }
    }
philip's avatar
philip committed
529
530
    #endif
    #if USE_NETMIDI
philip's avatar
philip committed
531
    if (source == SourceNet){
philip's avatar
philip committed
532
        if (net_to_usb()){
philip's avatar
philip committed
533
534
            usbmidi_tx(buffer, length);
        }
philip's avatar
philip committed
535
        if (net_to_midi()){
philip's avatar
philip committed
536
537
538
            netmidi_tx(buffer, length);
        }
    }
philip's avatar
philip committed
539
    #endif
philip's avatar
philip committed
540
541
}

philip's avatar
..    
philip committed
542
#if USE_NRPN_CONTROL
philip's avatar
philip committed
543
544
void controller_handle_nrpn(uint8_t channel, MidiMessage::NRpnType_t type, MidiMessage::NRpnAction_t action,  uint16_t controller, uint16_t value, Source source)
{
philip's avatar
..    
philip committed
545
    #if USE_CONTROLLER_LOGIC == 1
philip's avatar
philip committed
546
547
548
549
    if (type == MidiMessage::NRpnTypeNRPN && channel == get_channel()){
        if (action == MidiMessage::NRpnActionValue){
            int32_t motori = controller - CC_CONTROLLER_OFFSET;
            // printf("controller %d\n", motori);
philip's avatar
?    
philip committed
550

philip's avatar
philip committed
551
552
553
554
555
            if (0 <= motori && motori < MOTOR_COUNT){
                float pos = u14_to_pos(value);
                // printf("motor[%d] = %d\n", motori, (int)(pos*100));
                motors[motori] = pos;
            }
philip's avatar
?    
philip committed
556
557
        }
    }
philip's avatar
..    
philip committed
558
    #endif //USE_CONTROLLER_LOGIC == 1
philip's avatar
philip committed
559
}
philip's avatar
..    
philip committed
560
#endif //USE_NRPN_CONTROL
philip's avatar
philip committed
561

philip's avatar
philip committed
562
563
564
565
566

#if USE_USBMIDI == 1

void usbmidi_init()
{
philip's avatar
philip committed
567
568
569
570
571
572
573
    // usbmidi.attach(do_nothing);
    // [](){
    //     // do nothing (it's really sad, but if there is no callback attached, it doesn't work...)
    // });

    static uint8_t buffer[128];

philip's avatar
philip committed
574
575
576
577
578
579
580
    MidiMessage::simpleparser_init(
        &usbmidi_parser,
        true, // enable running status
        (uint8_t*)&buffer, sizeof(buffer),
        [](uint8_t * buffer, uint16_t length, void * context){
            controller_handle_msg(buffer, length, SourceUsb);
        },
philip's avatar
..    
philip committed
581
        #if USE_NRPN_CONTROL
philip's avatar
philip committed
582
583
584
        [](uint8_t channel, MidiMessage::NRpnType_t type, MidiMessage::NRpnAction_t action,  uint16_t controller, uint16_t value, void * context){
            controller_handle_nrpn(channel, type, action, controller, value, SourceUsb);
        },
philip's avatar
philip committed
585
586
587
        #else
        NULL,
        #endif
philip's avatar
philip committed
588
589
590
        NULL,
        NULL
    );
philip's avatar
philip committed
591
592
}

philip's avatar
philip committed
593
void usbmidi_run()
philip's avatar
philip committed
594
{
philip's avatar
philip committed
595
    usb_led1 = usbmidi.connected();
philip's avatar
philip committed
596
597
598
599

    if (usbmidi.connected() == false){

        if (usbmidi.just_reconnected()){
philip's avatar
test    
philip committed
600
            // midi_tx((uint8_t*)"1\n", 2);
philip's avatar
philip committed
601
602
603
604
605
606
            usbmidi.connect();
        }

        return;
    } 

philip's avatar
test    
philip committed
607
    // printf("usbmidi.ready() = %d\n", usbmidi.ready());
philip's avatar
philip committed
608
    if (!usbmidi.ready()){
philip's avatar
philip committed
609
610
611
        return;
    }

philip's avatar
test    
philip committed
612
    
philip's avatar
philip committed
613
    if (usbmidi.readable()){
philip's avatar
philip committed
614
        // printf("ubsmidi.readable() = %d\n", usbmidi.readable());    
philip's avatar
philip committed
615
        // mark activity
philip's avatar
test    
philip committed
616
        // usbmidi_led = 0;
philip's avatar
philip committed
617

philip's avatar
philip committed
618
619
        MIDIMessage msg;

620
        usbmidi.read(msg);
philip's avatar
philip committed
621

622
        if (msg.length == 0){
philip's avatar
philip committed
623
624
625
            return;
        }

626
627
        // MIDIMessage can contain multiple messages, thus we have to parse them like a stream...
        MidiMessage::simpleparser_receivedData(&usbmidi_parser, msg.data, (uint8_t)msg.length);
philip's avatar
philip committed
628
629
630
631
632
633
634
635
636
    }
}

void usbmidi_tx(uint8_t * buffer, size_t length)
{
    if (usbmidi.ready() == false){
        return;
    }

637
    usbmidi.write(buffer, length);
philip's avatar
philip committed
638
}
philip's avatar
philip committed
639

philip's avatar
philip committed
640
641
642
643
644
645
646
#endif //USE_USBMIDI == 1


#if USE_MIDI == 1

void midi_init()
{
philip's avatar
philip committed
647
648
    printf("midi_init()\n");

philip's avatar
philip committed
649
    // setup MIDI UART according to specs
philip's avatar
philip committed
650
651
    midi.set_baud(MIDI_BAUD); // 31.25kbaud
    midi.set_format(MIDI_BITS, MIDI_PARITY, MIDI_STOP); // 8 data bits, no parity, 1 stop bit
philip's avatar
philip committed
652
653
654
655
    midi.set_flow_control(BufferedSerial::Disabled);

    midi.set_blocking(false);

philip's avatar
philip committed
656
    static uint8_t buffer[128];
philip's avatar
philip committed
657

philip's avatar
philip committed
658
659
660
661
662
663
664
    MidiMessage::simpleparser_init(
        &midi_parser,
        true, // enable running status
        (uint8_t*)&buffer, sizeof(buffer),
        [](uint8_t * buffer, uint16_t length, void * context){
            controller_handle_msg(buffer, length, SourceMidi);
        },
philip's avatar
..    
philip committed
665
        #if USE_NRPN_CONTROL
philip's avatar
philip committed
666
667
668
        [](uint8_t channel, MidiMessage::NRpnType_t type, MidiMessage::NRpnAction_t action,  uint16_t controller, uint16_t value, void * context){
            controller_handle_nrpn(channel, type, action, controller, value, SourceMidi);
        },
philip's avatar
philip committed
669
670
671
        #else
        NULL,
        #endif
philip's avatar
philip committed
672
673
674
        NULL,
        NULL
    );
philip's avatar
philip committed
675
676
}

philip's avatar
philip committed
677
678
679
void midi_run()
{
    static uint8_t buffer[128];
philip's avatar
philip committed
680

philip's avatar
philip committed
681
682
683
684
685
686
687
688
689
690
    if (midi.readable()){

        size_t rlen = midi.read(buffer, sizeof(buffer));

        if (rlen > 0){
            MidiMessage::simpleparser_receivedData(&midi_parser, buffer, (uint8_t)rlen);
        }
    }
}

philip's avatar
philip committed
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
void midi_tx(uint8_t * buffer, size_t length)
{
    if (midi.writable() == false){
        return;
    }

    midi.write(buffer, length);
}
    
#endif //USE_MIDI == 1

#if USE_NETMIDI == 1

void netmidi_init()
{
philip's avatar
philip committed
706
707
    // low-level enable multicast pass all 
    WRITE_REG(ETH->MACPFR, READ_REG(ETH->MACPFR) | (1 << 4));
philip's avatar
philip committed
708

philip's avatar
philip committed
709
710
711
    const char * mac = eth.get_mac_address();
    printf("mac %s\n", mac ? mac : "none");

philip's avatar
philip committed
712

philip's avatar
philip committed
713
    eth.add_event_listener(eth_status_changed);
philip's avatar
philip committed
714

philip's avatar
philip committed
715
    
philip's avatar
philip committed
716
717
718
719
720
721
722
723
724
    if (udp_sock.open(&eth)){
        printf("udp_sock: open error\n");
        return;
    }
    if (udp_sock.bind(7)){
        printf("udp_sock: bind error\n");
        return;
    }
    udp_sock.set_blocking(false);
philip's avatar
philip committed
725
726
727

    net_thread.start(eth_ifup);
}
philip's avatar
philip committed
728

philip's avatar
philip committed
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
void eth_status_changed(nsapi_event_t evt, intptr_t intptr)
{
    if (evt != NSAPI_EVENT_CONNECTION_STATUS_CHANGE){
        return;
    }

    static bool eth_was_up = false;

    switch(eth.get_connection_status()){
        case NSAPI_STATUS_LOCAL_UP: 
            printf("eth local up\n");
            return;

        case NSAPI_STATUS_GLOBAL_UP:
            eth_was_up = true;
philip's avatar
philip committed
744
            printf("eth global up\n");
philip's avatar
philip committed
745
746
747
748
749
750
751
752
753
754
755
            return;

        case NSAPI_STATUS_DISCONNECTED: 
            printf("eth disconnected!\n");
            return;

        case NSAPI_STATUS_CONNECTING:
            printf("eth connecting\n");
            if (eth_was_up){
                eth_was_up = false;
                eth_reconnect = true;
philip's avatar
philip committed
756
                mdns_deinit();
philip's avatar
philip committed
757
758
759
760
761
762
763
764
765
766
767
768
769
                printf("should reconnect\n");
                // eth.disconnect();
            }
            return;

        case NSAPI_STATUS_ERROR_UNSUPPORTED:
            printf("eth unsupported\n");
            return;
    }
}

bool eth_connect()
{
philip's avatar
philip committed
770
    
philip's avatar
philip committed
771
772
773
774
775
776
777
778
779
780
781
    // printf("eth.status = %d\n", eth.get_connection_status());
    if (eth.get_connection_status() != NSAPI_STATUS_DISCONNECTED){
        eth.disconnect();
    }

    eth.set_default_parameters();

    // to force dhcp
    eth.set_network("0.0.0.0", "0.0.0.0", "0.0.0.0");

    int res;
philip's avatar
philip committed
782
    
philip's avatar
philip committed
783
784
    do {
        res = eth.connect();
philip's avatar
philip committed
785
    } while( res != NSAPI_ERROR_OK && res != NSAPI_ERROR_DHCP_FAILURE );
philip's avatar
philip committed
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802

    if (res == NSAPI_ERROR_OK) {
    
        // Show the network address
        eth.get_ip_address(&ip);
        printf("%s: %s\n", ip.get_ip_version() == NSAPI_IPv4 ? "ipv4" : "ipv6", ip.get_ip_address());

        return true;
    }

    if (res != NSAPI_ERROR_DHCP_FAILURE){
        printf("connect failed: %d\n", res);
        return false;
    }

    printf("dhcp timeout\n");

philip's avatar
philip committed
803

philip's avatar
philip committed
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
    res = eth.get_ipv6_link_local_address(&ip);

    if (res == NSAPI_ERROR_OK){
        printf("ipv6 link-local: %s\n", ip.get_ip_address());
        return true;
    }

    if (res == NSAPI_ERROR_UNSUPPORTED){
        printf("ipv6 link-local not supported\n");
    } else {
        printf("ipv6 link-local fail: %d\n", res);
    }

    // has to disconnect to set manual address
    eth.disconnect();

    // setup ipv4 link-local address
philip's avatar
philip committed
821
822
    uint8_t s3 = (((hw_device_id >> 24) ^ (hw_device_id >> 16)) % 254) + 1;
    uint8_t s4 = (hw_device_id >> 8) ^ hw_device_id;
philip's avatar
philip committed
823
824
825
    char ll[20] = "";
    sprintf(ll, "169.254.%hhu.%hhu", s3, s4);
    ip.set_ip_address(ll);
philip's avatar
philip committed
826
827


philip's avatar
philip committed
828
829
830
831
832
833
834
835
836
    printf("Using ipv4 link-local: %s/16\n", ll);
    eth.set_network(ip, "255.255.0.0", "0.0.0.0");

    if (eth.connect()){
        printf("link-local connect fail!\n");
        return false;
    } 

    return true;
philip's avatar
philip committed
837
838
}

philip's avatar
philip committed
839
void mdns_init()
philip's avatar
philip committed
840
{
philip's avatar
philip committed
841
    memset(mdns_records, 0, sizeof(mdns_records));
philip's avatar
philip committed
842
843
844
845

    if (ip.get_ip_version() == NSAPI_IPv4){
        memcpy(RR_A.ipv4, ip.get_ip_bytes(), sizeof(RR_A.ipv4));

philip's avatar
philip committed
846
847
848
849
850
        sprintf((char*)RR_A.name, NET_HOSTNAME_FMT, get_device_id());
        printf("A.name %s\n", (char*)RR_A.name);

        minimr_dns_normalize_name(RR_A.name, &RR_A.name_length);

philip's avatar
philip committed
851
852
853
854
855
856
857
        mdns_records[0] = (struct minimr_dns_rr *)&RR_A;

        mdns_addr.set_ip_address("224.0.0.251");
        mdns_addr.set_port(5353);
    } else {
        memcpy(RR_AAAA.ipv6, ip.get_ip_bytes(), sizeof(RR_AAAA.ipv6));

philip's avatar
philip committed
858
859
860
861
862
863
        sprintf((char*)RR_AAAA.name, NET_HOSTNAME_FMT, get_device_id());
        printf("AAAA.name %s\n", (char*)RR_AAAA.name);

        minimr_dns_normalize_name(RR_AAAA.name, &RR_AAAA.name_length);


philip's avatar
philip committed
864
865
866
867
868
869
        mdns_records[0] = (struct minimr_dns_rr *)&RR_AAAA;

        mdns_addr.set_ip_address("ff02::fb");
        mdns_addr.set_port(5353);
    }

philip's avatar
philip committed
870
871
872
873
874
875
876
877
878
879
880

    if (mdns_sock.open(&eth)){
        printf("mdns_sock: open error\n");
        return;
    }
    if (mdns_sock.bind(5353)){
        printf("mdns_sock: bind error\n");
        return;
    }
    mdns_sock.set_blocking(false);

philip's avatar
philip committed
881
882
883
884
885
886
887
    if (mdns_sock.join_multicast_group(mdns_addr)){
        printf("mdns_sock: failed to join multicast grp\n");
        return;
    }
    
}

philip's avatar
philip committed
888
889
890
891
892
893
894
895
896
897
898
void mdns_deinit()
{
    if (mdns_sock.leave_multicast_group(mdns_addr)){
        printf("mdns_sock: failed leave multicast group\n");
    }

    if (mdns_sock.close()){
        printf("mdns_sock: failed close\n");
    }
}

philip's avatar
philip committed
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
int mdns_rr_callback(enum minimr_dns_rr_fun_type type, struct minimr_dns_rr * rr, ...)
{
    if (type == minimr_dns_rr_fun_type_respond_to){
        // always respond
        return MINIMR_RESPOND;
    }

    // it isn't necessarily safe to put this here

    va_list args;
    va_start(args, rr);

    uint8_t * outmsg = va_arg(args, uint8_t *);
    uint16_t * outmsglen = va_arg(args, uint16_t *);
    uint16_t outmsgmaxlen = va_arg(args, int); // uint16_t will be promoted to int
    uint16_t * nrr = va_arg(args, uint16_t *);

    va_end(args);


    if (type == minimr_dns_rr_fun_type_get_rr){
        if ((rr->type == MINIMR_DNS_TYPE_A && outmsgmaxlen < MINIMR_DNS_RR_A_SIZE(rr->name_length)) ||
            (rr->type == MINIMR_DNS_TYPE_AAAA && outmsgmaxlen < MINIMR_DNS_RR_AAAA_SIZE(rr->name_length))) {
            return MINIMR_NOT_OK;
        }

        uint16_t l = *outmsglen;

        // helper macros to write all the standard fields of the record
        // you can naturally do this manually and customize it ;)

        MINIMR_DNS_RR_WRITE_COMMON(outmsg, l, rr->name, rr->name_length, rr->type, rr->cache_class, rr->ttl);

        if (rr->type == MINIMR_DNS_TYPE_A) {
            MINIMR_DNS_RR_WRITE_A_BODY(outmsg, l, ((minimr_dns_rr_a*)rr)->ipv4);
        }
        else if (rr->type == MINIMR_DNS_TYPE_AAAA) {
            MINIMR_DNS_RR_WRITE_AAAA_BODY(outmsg, l, ((minimr_dns_rr_aaaa*)rr)->ipv6);
        }
        else {
            return MINIMR_NOT_OK;
        }

        *outmsglen = l;
        *nrr = 1;
    }

    return MINIMR_OK;
}


philip's avatar
philip committed
950
void eth_ifup()
philip's avatar
philip committed
951
{
philip's avatar
philip committed
952
953
954
955
    printf("eth_ifup()\n");

    eth_reconnect = true;

philip's avatar
philip committed
956
957
958
959
960
961
    uint8_t mdns_in[1024];
    uint8_t mdns_out[1024];
    uint16_t mdns_inlen = 0;
    uint16_t mdns_outlen = 0;

    int res = 0;
962

philip's avatar
philip committed
963
964
    while (1){

philip's avatar
philip committed
965
        if (eth.get_connection_status() != NSAPI_STATUS_GLOBAL_UP){
philip's avatar
test    
philip committed
966

philip's avatar
philip committed
967
968
969
970
            if (eth_reconnect == false){
                wait_us(1000000);
                continue;
            }
philip's avatar
test    
philip committed
971

philip's avatar
philip committed
972
973
974
            if (eth_connect() == false){
                return;
            }
philip's avatar
philip committed
975

philip's avatar
philip committed
976
            eth_reconnect = false;
philip's avatar
test    
philip committed
977

philip's avatar
philip committed
978
            
philip's avatar
philip committed
979
            mdns_init();
philip's avatar
philip committed
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995

            // only announcing twice
            res = minimr_announce(mdns_records, MDNS_RR_COUNT, mdns_out, &mdns_outlen, sizeof(mdns_out), NULL);

            if (res != MINIMR_OK){
                printf("minimr_announce: failed %d\n", res);
                continue;
            }

            if (mdns_outlen > 0){
                // mdns_sock.set_blocking(false);
                mdns_sock.sendto(mdns_addr, mdns_out, mdns_outlen);
                wait_us(1000000);
                mdns_sock.sendto(mdns_addr, mdns_out, mdns_outlen);
                mdns_sock.set_blocking(false);
            }
philip's avatar
philip committed
996
        }
philip's avatar
philip committed
997

philip's avatar
philip committed
998
        
philip's avatar
philip committed
999
1000
        // check if there is an mdns message and react to it
        SocketAddress addr;
For faster browsing, not all history is shown. View entire blame