main.cpp 27.5 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
409
410
411
412
    if (btn_plus2_touched){
        if (motors_running){
            motors_suspend();
        } else {
            motors_resume();
        }
        btn_plus2_touched = false;
    }

philip's avatar
philip committed
413
414
415
416
417
    if (motors_center_request){
        motors_center();
        motors_center_request = false;
    }

philip's avatar
philip committed
418
    bool is_off = motors_running == false;
philip's avatar
philip committed
419

philip's avatar
..    
philip committed
420
421
    for(int i = 0; i < MOTOR_COUNT; i++){
        motors[i].run();
philip's avatar
philip committed
422

philip's avatar
philip committed
423
        is_off |= motors[i].get_state() == false;
philip's avatar
..    
philip committed
424
    }
philip's avatar
philip committed
425
426

    led_motors = is_off;
philip's avatar
philip committed
427
428
}

philip's avatar
philip committed
429
430
431
432
433
434
435
void motors_center()
{
    for(int i = 0; i < MOTOR_COUNT; i++){
        motors[i] = 0.5;
    }
}

philip's avatar
..    
philip committed
436

philip's avatar
philip committed
437
438
void controller_handle_msg(uint8_t * buffer, size_t length, Source source)
{
philip's avatar
philip committed
439
440
441
442
443
    // printf("CMD (len %d) ", length);
    // for(int i = 0; i < length; i++){
    //     printf("%02x", buffer[i]);
    // }
    // printf("\n");
philip's avatar
philip committed
444

445

philip's avatar
..    
philip committed
446
447
    #if USE_CONTROLLER_LOGIC == 1

philip's avatar
philip committed
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
    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
464
        #if USE_SYSTEM_RESET == 1
philip's avatar
philip committed
465
466
467
        // 0xFF = reset
        if (msg.data[0] == 0xFF){
            system_reset();
philip's avatar
philip committed
468
            printf("system_reset??\n");
philip's avatar
philip committed
469
        }
philip's avatar
philip committed
470
        #else
philip's avatar
..    
philip committed
471
        printf("USE_SYSTEM_RESET == 0\n");
philip's avatar
philip committed
472
473
474
475
        #endif
    }


philip's avatar
..    
philip committed
476
    // position control
philip's avatar
philip committed
477
    if (msg.type() == MIDIMessage::ControlChangeType){
philip's avatar
philip committed
478
        if (msg.channel() == get_channel()){
philip's avatar
philip committed
479
            int32_t motori = msg.controller() - CC_CONTROLLER_OFFSET;
philip's avatar
philip committed
480
481
482

            if (0 <= motori && motori < MOTOR_COUNT){
                float pos = u7_to_pos(msg.value());
philip's avatar
philip committed
483
                // printf("motor[%d] = %d\n", motori, (int)(pos*100));
philip's avatar
philip committed
484
485
486
487
488
                motors[motori] = pos;
            }
        }
    }

philip's avatar
..    
philip committed
489
    #if USE_PITCHBEND_CONTROL
philip's avatar
philip committed
490
    // each channel controls a motor starting from channel_offset
philip's avatar
?    
philip committed
491
492
    if (msg.type() == MIDIMessage::PitchWheelType){
        int32_t motori = msg.channel();
philip's avatar
philip committed
493
        
philip's avatar
?    
philip committed
494
495
496
497
        if (0 <= motori && motori < MOTOR_COUNT){
            float pos = s14_to_pos(msg.pitch());
            motors[motori] = pos;
        }
philip's avatar
philip committed
498
        
philip's avatar
?    
philip committed
499
    }
philip's avatar
..    
philip committed
500
    #endif //USE_PITCHBEND_CONTROL
philip's avatar
philip committed
501

philip's avatar
..    
philip committed
502
    // power control
philip's avatar
philip committed
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
    #if USE_CFG
    // only enable power pin iff cfg2 is enabled
    if (cfg2.read()){
    #else
    {
    #endif
        if (msg.type() == MIDIMessage::NoteOnType || msg.type() == MIDIMessage::NoteOffType){
            if (msg.channel() == get_channel()){
                int32_t motori = msg.key();

                if (0 <= motori && motori < MOTOR_COUNT){
                    // turn on or off
                    bool off = msg.type() == MIDIMessage::NoteOffType || msg.velocity() == 0;
                    // printf("motor pwr %d := %d\n", motori, !off);
                    motors[motori] = !off;
                }
philip's avatar
..    
philip committed
519
520
521
522
523
524
            }
        }
    }


    #endif //USE_CONTROLLER_LOGIC == 1
525

philip's avatar
philip committed
526
    #if USE_USBMIDI
philip's avatar
philip committed
527
    if (source == SourceUsb){
philip's avatar
philip committed
528
        if (usb_to_midi()){
philip's avatar
philip committed
529
530
            midi_tx(buffer, length);
        }
philip's avatar
philip committed
531
        if (usb_to_net()){
philip's avatar
philip committed
532
533
534
            netmidi_tx(buffer, length);
        }
    }
philip's avatar
philip committed
535
536
    #endif
    #if USE_MIDI
philip's avatar
philip committed
537
    if (source == SourceMidi){
philip's avatar
philip committed
538
        if (midi_to_usb()){
philip's avatar
philip committed
539
540
            usbmidi_tx(buffer, length);
        }
philip's avatar
philip committed
541
        if (midi_to_net()){
philip's avatar
philip committed
542
543
544
            netmidi_tx(buffer, length);
        }
    }
philip's avatar
philip committed
545
546
    #endif
    #if USE_NETMIDI
philip's avatar
philip committed
547
    if (source == SourceNet){
philip's avatar
philip committed
548
        if (net_to_usb()){
philip's avatar
philip committed
549
550
            usbmidi_tx(buffer, length);
        }
philip's avatar
philip committed
551
        if (net_to_midi()){
philip's avatar
philip committed
552
553
554
            netmidi_tx(buffer, length);
        }
    }
philip's avatar
philip committed
555
    #endif
philip's avatar
philip committed
556
557
}

philip's avatar
..    
philip committed
558
#if USE_NRPN_CONTROL
philip's avatar
philip committed
559
560
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
561
    #if USE_CONTROLLER_LOGIC == 1
philip's avatar
philip committed
562
563
564
565
    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
566

philip's avatar
philip committed
567
568
569
570
571
            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
572
573
        }
    }
philip's avatar
..    
philip committed
574
    #endif //USE_CONTROLLER_LOGIC == 1
philip's avatar
philip committed
575
}
philip's avatar
..    
philip committed
576
#endif //USE_NRPN_CONTROL
philip's avatar
philip committed
577

philip's avatar
philip committed
578
579
580
581
582

#if USE_USBMIDI == 1

void usbmidi_init()
{
philip's avatar
philip committed
583
584
585
586
587
588
589
    // 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
590
591
592
593
594
595
596
    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
597
        #if USE_NRPN_CONTROL
philip's avatar
philip committed
598
599
600
        [](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
601
602
603
        #else
        NULL,
        #endif
philip's avatar
philip committed
604
605
606
        NULL,
        NULL
    );
philip's avatar
philip committed
607
608
}

philip's avatar
philip committed
609
void usbmidi_run()
philip's avatar
philip committed
610
{
philip's avatar
philip committed
611
    usb_led1 = usbmidi.connected();
philip's avatar
philip committed
612
613
614
615

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

        if (usbmidi.just_reconnected()){
philip's avatar
test    
philip committed
616
            // midi_tx((uint8_t*)"1\n", 2);
philip's avatar
philip committed
617
618
619
620
621
622
            usbmidi.connect();
        }

        return;
    } 

philip's avatar
test    
philip committed
623
    // printf("usbmidi.ready() = %d\n", usbmidi.ready());
philip's avatar
philip committed
624
    if (!usbmidi.ready()){
philip's avatar
philip committed
625
626
627
        return;
    }

philip's avatar
test    
philip committed
628
    
philip's avatar
philip committed
629
    if (usbmidi.readable()){
philip's avatar
philip committed
630
        // printf("ubsmidi.readable() = %d\n", usbmidi.readable());    
philip's avatar
philip committed
631
        // mark activity
philip's avatar
test    
philip committed
632
        // usbmidi_led = 0;
philip's avatar
philip committed
633

philip's avatar
philip committed
634
635
        MIDIMessage msg;

636
        usbmidi.read(msg);
philip's avatar
philip committed
637

638
        if (msg.length == 0){
philip's avatar
philip committed
639
640
641
            return;
        }

642
643
        // 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
644
645
646
647
648
649
650
651
652
    }
}

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

653
    usbmidi.write(buffer, length);
philip's avatar
philip committed
654
}
philip's avatar
philip committed
655

philip's avatar
philip committed
656
657
658
659
660
661
662
#endif //USE_USBMIDI == 1


#if USE_MIDI == 1

void midi_init()
{
philip's avatar
philip committed
663
664
    printf("midi_init()\n");

philip's avatar
philip committed
665
    // setup MIDI UART according to specs
philip's avatar
philip committed
666
667
    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
668
669
670
671
    midi.set_flow_control(BufferedSerial::Disabled);

    midi.set_blocking(false);

philip's avatar
philip committed
672
    static uint8_t buffer[128];
philip's avatar
philip committed
673

philip's avatar
philip committed
674
675
676
677
678
679
680
    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
681
        #if USE_NRPN_CONTROL
philip's avatar
philip committed
682
683
684
        [](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
685
686
687
        #else
        NULL,
        #endif
philip's avatar
philip committed
688
689
690
        NULL,
        NULL
    );
philip's avatar
philip committed
691
692
}

philip's avatar
philip committed
693
694
695
void midi_run()
{
    static uint8_t buffer[128];
philip's avatar
philip committed
696

philip's avatar
philip committed
697
698
699
700
701
702
703
704
705
706
    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
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
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
722
723
    // low-level enable multicast pass all 
    WRITE_REG(ETH->MACPFR, READ_REG(ETH->MACPFR) | (1 << 4));
philip's avatar
philip committed
724

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

philip's avatar
philip committed
728

philip's avatar
philip committed
729
    eth.add_event_listener(eth_status_changed);
philip's avatar
philip committed
730

philip's avatar
philip committed
731
    
philip's avatar
philip committed
732
733
734
735
736
737
738
739
740
    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
741
742
743

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

philip's avatar
philip committed
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
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
760
            printf("eth global up\n");
philip's avatar
philip committed
761
762
763
764
765
766
767
768
769
770
771
            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
772
                mdns_deinit();
philip's avatar
philip committed
773
774
775
776
777
778
779
780
781
782
783
784
785
                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
786
    
philip's avatar
philip committed
787
788
789
790
791
792
793
794
795
796
797
    // 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
798
    
philip's avatar
philip committed
799
800
    do {
        res = eth.connect();
philip's avatar
philip committed
801
    } while( res != NSAPI_ERROR_OK && res != NSAPI_ERROR_DHCP_FAILURE );
philip's avatar
philip committed
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818

    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
819

philip's avatar
philip committed
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
    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
837
838
    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
839
840
841
    char ll[20] = "";
    sprintf(ll, "169.254.%hhu.%hhu", s3, s4);
    ip.set_ip_address(ll);
philip's avatar
philip committed
842
843


philip's avatar
philip committed
844
845
846
847
848
849
850
851
852
    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
853
854
}

philip's avatar
philip committed
855
void mdns_init()
philip's avatar
philip committed
856
{
philip's avatar
philip committed
857
    memset(mdns_records, 0, sizeof(mdns_records));
philip's avatar
philip committed
858
859
860
861

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

philip's avatar
philip committed
862
863
864
865
866
        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
867
868
869
870
871
872
873
        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
874
875
876
877
878
879
        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
880
881
882
883
884
885
        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
886
887
888
889
890
891
892
893
894
895
896

    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
897
898
899
900
901
902
903
    if (mdns_sock.join_multicast_group(mdns_addr)){
        printf("mdns_sock: failed to join multicast grp\n");
        return;
    }
    
}

philip's avatar
philip committed
904
905
906
907
908
909
910
911
912
913
914
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
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
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
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
966
void eth_ifup()
philip's avatar
philip committed
967
{
philip's avatar
philip committed
968
969
970
971
    printf("eth_ifup()\n");

    eth_reconnect = true;

philip's avatar
philip committed
972
973
974
975
976
977
    uint8_t mdns_in[1024];
    uint8_t mdns_out[1024];
    uint16_t mdns_inlen = 0;
    uint16_t mdns_outlen = 0;

    int res = 0;
978

philip's avatar
philip committed
979
980
    while (1){

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

philip's avatar
philip committed
983
984
985
986
            if (eth_reconnect == false){
                wait_us(1000000);
                continue;
            }
philip's avatar
test    
philip committed
987

philip's avatar
philip committed
988
989
990
            if (eth_connect() == false){
                return;
            }
philip's avatar
philip committed
991

philip's avatar
philip committed
992
            eth_reconnect = false;
philip's avatar
test    
philip committed
993

philip's avatar
philip committed
994
            
philip's avatar
philip committed
995
            mdns_init();
philip's avatar
philip committed
996
997
998
999
1000

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

            if (res != MINIMR_OK){
For faster browsing, not all history is shown. View entire blame