Преглед на файлове

pmw frame and data capture mode and visualization scripts.

Thomas Buck преди 1 година
родител
ревизия
d4ecc9ce11

+ 1
- 1
firmware/include/config.h Целия файл

@@ -14,6 +14,6 @@
14 14
 
15 15
 #define INVERT_MOUSE_X_AXIS false
16 16
 #define INVERT_MOUSE_Y_AXIS true
17
-#define DEFAULT_MOUSE_SENSITIVITY PMW_CPI_TO_SENSE(800)
17
+#define DEFAULT_MOUSE_SENSITIVITY PMW_CPI_TO_SENSE(500)
18 18
 
19 19
 #endif // __CONFIG_H__

+ 2
- 1
firmware/include/log.h Целия файл

@@ -14,7 +14,8 @@
14 14
         ##__VA_ARGS__)
15 15
 
16 16
 // for interactive output. is not stored or re-played.
17
-#define print(fmt, ...) debug_log(false, fmt "\r\n", ##__VA_ARGS__)
17
+#define print(fmt, ...) debug_log(false, fmt, ##__VA_ARGS__)
18
+#define println(fmt, ...) debug_log(false, fmt "\r\n", ##__VA_ARGS__)
18 19
 
19 20
 void debug_log(bool log, const char *format, ...) __attribute__((format(printf, 2, 3)));
20 21
 void log_dump_to_usb(void);

+ 7
- 0
firmware/include/pmw3360.h Целия файл

@@ -5,6 +5,8 @@
5 5
 #ifndef __PMW3360_H__
6 6
 #define __PMW3360_H__
7 7
 
8
+#include <sys/types.h>
9
+
8 10
 struct pmw_motion {
9 11
     bool motion;
10 12
     int32_t delta_x;
@@ -12,6 +14,7 @@ struct pmw_motion {
12 14
 };
13 15
 
14 16
 int pmw_init(void);
17
+void pmw_run(void);
15 18
 bool pmw_is_alive(void);
16 19
 
17 20
 struct pmw_motion pmw_get(void);
@@ -31,5 +34,9 @@ uint8_t pmw_get_sensitivity(void);
31 34
 #define PMW_CPI_TO_SENSE(cpi) ((cpi / 100) - 1)
32 35
 
33 36
 void pmw_print_status(void);
37
+void pmw_dump_data(void);
38
+
39
+ssize_t pmw_frame_capture(uint8_t *buff, size_t buffsize);
40
+#define PMW_FRAME_CAPTURE_LEN 1296
34 41
 
35 42
 #endif // __PMW3360_H__

+ 2
- 0
firmware/include/util.h Целия файл

@@ -15,4 +15,6 @@ bool str_startswith(const char *str, const char *start);
15 15
 void reset_to_bootloader(void);
16 16
 void reset_to_main(void);
17 17
 
18
+void hexdump(uint8_t *buff, size_t len);
19
+
18 20
 #endif // __UTIL_H__

+ 41
- 25
firmware/src/console.c Целия файл

@@ -30,9 +30,9 @@ static void cnsl_interpret(const char *line) {
30 30
     if (strlen(line) == 0) {
31 31
         if ((strlen(cnsl_last_command) > 0) && (strcmp(cnsl_last_command, "repeat") != 0)) {
32 32
             // repeat last command once
33
-            print("repeating command \"%s\"", cnsl_last_command);
33
+            println("repeating command \"%s\"", cnsl_last_command);
34 34
             cnsl_interpret(cnsl_last_command);
35
-            print();
35
+            println();
36 36
         }
37 37
         return;
38 38
     } else if (strcmp(line, "repeat") == 0) {
@@ -48,50 +48,66 @@ static void cnsl_interpret(const char *line) {
48 48
     } else if ((strcmp(line, "help") == 0)
49 49
             || (strcmp(line, "h") == 0)
50 50
             || (strcmp(line, "?") == 0)) {
51
-        print("Trackball Firmware Usage:");
52
-        print("    cpi - print current sensitivity");
53
-        print("  cpi N - set sensitivity");
54
-        print("   pmws - print PMW3360 status");
55
-        print("   pmwr - reset PMW3360");
56
-        print("  reset - reset back into this firmware");
57
-        print("   \\x18 - reset to bootloader");
58
-        print(" repeat - repeat last command every %d milliseconds", CNSL_REPEAT_MS);
59
-        print("   help - print this message");
60
-        print("Press Enter with no input to repeat last command.");
61
-        print("Use repeat to continuously execute last command.");
62
-        print("Stop this by calling repeat again.");
51
+        println("Trackball Firmware Usage:");
52
+        println("    cpi - print current sensitivity");
53
+        println("  cpi N - set sensitivity");
54
+        println("   pmws - print PMW3360 status");
55
+        println("   pmwf - print PMW3360 frame capture");
56
+        println("   pmwd - print PMW3360 data dump");
57
+        println("   pmwr - reset PMW3360");
58
+        println("  reset - reset back into this firmware");
59
+        println("   \\x18 - reset to bootloader");
60
+        println(" repeat - repeat last command every %d milliseconds", CNSL_REPEAT_MS);
61
+        println("   help - print this message");
62
+        println("Press Enter with no input to repeat last command.");
63
+        println("Use repeat to continuously execute last command.");
64
+        println("Stop this by calling repeat again.");
63 65
     } else if (strcmp(line, "pmws") == 0) {
64 66
         pmw_print_status();
67
+    } else if (strcmp(line, "pmwd") == 0) {
68
+        pmw_dump_data();
69
+    } else if (strcmp(line, "pmwf") == 0) {
70
+        uint8_t frame[PMW_FRAME_CAPTURE_LEN];
71
+        ssize_t r = pmw_frame_capture(frame, PMW_FRAME_CAPTURE_LEN);
72
+        if (r == PMW_FRAME_CAPTURE_LEN) {
73
+            println("PMW3360 frame capture:");
74
+            hexdump(frame, PMW_FRAME_CAPTURE_LEN);
75
+
76
+            println("Re-Initializing PMW3360");
77
+            pmw_init();
78
+        } else {
79
+            println("error capturing frame (%d)", r);
80
+        }
65 81
     } else if (strcmp(line, "pmwr") == 0) {
66
-        print("user requests re-initializing of PMW3360");
82
+        println("user requests re-initializing of PMW3360");
67 83
         int r = pmw_init();
68 84
         if (r < 0) {
69
-            print("error initializing PMW3360");
85
+            println("error initializing PMW3360");
70 86
         } else {
71
-            print("PMW3360 re-initialized successfully");
87
+            println("PMW3360 re-initialized successfully");
72 88
         }
73 89
     } else if (strcmp(line, "cpi") == 0) {
74 90
         uint8_t sense = pmw_get_sensitivity();
75 91
         uint16_t cpi = PMW_SENSE_TO_CPI(sense);
76
-        print("current cpi: %u (0x%02X)", cpi, sense);
92
+        println("current cpi: %u (0x%02X)", cpi, sense);
77 93
     } else if (str_startswith(line, "cpi ")) {
78 94
         const char *num_str = line + 4;
79 95
         uintmax_t num = strtoumax(num_str, NULL, 10);
80 96
         if ((num < 100) || (num > 12000)) {
81
-            print("invalid cpi %llu, needs to be %u <= cpi <= %u", num, 100, 12000);
97
+            println("invalid cpi %llu, needs to be %u <= cpi <= %u", num, 100, 12000);
82 98
         } else {
83 99
             num = PMW_CPI_TO_SENSE(num);
84
-            print("setting cpi to 0x%02llX", num);
100
+            println("setting cpi to 0x%02llX", num);
85 101
             pmw_set_sensitivity(num);
86 102
         }
87 103
     } else if (strcmp(line, "reset") == 0) {
88 104
         reset_to_main();
89 105
     } else {
90
-        print("unknown command \"%s\"", line);
106
+        println("unknown command \"%s\"", line);
91 107
         return;
92 108
     }
93 109
 
94
-    print();
110
+    println();
95 111
 }
96 112
 
97 113
 void cnsl_init(void) {
@@ -122,15 +138,15 @@ void cnsl_run(void) {
122 138
             && (strcmp(cnsl_repeated_command, "repeat") != 0)) {
123 139
         uint32_t now = to_ms_since_boot(get_absolute_time());
124 140
         if (now >= (last_repeat_time + CNSL_REPEAT_MS)) {
125
-            print("repeating command \"%s\"", cnsl_repeated_command);
141
+            println("repeating command \"%s\"", cnsl_repeated_command);
126 142
             cnsl_interpret(cnsl_repeated_command);
127
-            print();
143
+            println();
128 144
 
129 145
             last_repeat_time = now;
130 146
         }
131 147
     } else {
132 148
         if (repeat_command) {
133
-            print("nothing to repeat");
149
+            println("nothing to repeat");
134 150
         }
135 151
         repeat_command = false;
136 152
     }

+ 1
- 12
firmware/src/main.c Целия файл

@@ -12,9 +12,6 @@
12 12
 #include "usb.h"
13 13
 #include "pmw3360.h"
14 14
 
15
-#define HEALTH_CHECK_INTERVAL_MS 500
16
-static uint32_t last_health_check = 0;
17
-
18 15
 int main(void) {
19 16
     heartbeat_init();
20 17
 
@@ -41,15 +38,7 @@ int main(void) {
41 38
         heartbeat_run();
42 39
         usb_run();
43 40
         cnsl_run();
44
-
45
-        uint32_t now = to_ms_since_boot(get_absolute_time());
46
-        if (now >= (last_health_check + HEALTH_CHECK_INTERVAL_MS)) {
47
-            last_health_check = now;
48
-            if (!pmw_is_alive()) {
49
-                debug("PMW3360 is dead. resetting!");
50
-                while (1) { }
51
-            }
52
-        }
41
+        pmw_run();
53 42
     }
54 43
 
55 44
     return 0;

+ 123
- 22
firmware/src/pmw3360.c Целия файл

@@ -20,6 +20,7 @@
20 20
 #include "pico/stdlib.h"
21 21
 #include "pico/binary_info.h"
22 22
 #include "hardware/spi.h"
23
+#include "hardware/watchdog.h"
23 24
 
24 25
 #include "config.h"
25 26
 #include "log.h"
@@ -28,12 +29,15 @@
28 29
 #include "pmw3360_srom.h"
29 30
 #include "pmw3360.h"
30 31
 
32
+#define HEALTH_CHECK_INTERVAL_MS 1000
33
+
31 34
 #if !defined(spi_default) || !defined(PICO_DEFAULT_SPI_SCK_PIN) || !defined(PICO_DEFAULT_SPI_TX_PIN) || !defined(PICO_DEFAULT_SPI_RX_PIN) || !defined(PICO_DEFAULT_SPI_CSN_PIN)
32 35
 #error PMW3360 API requires a board with SPI pins
33 36
 #endif
34 37
 
35 38
 static volatile int32_t delta_x = 0, delta_y = 0;
36 39
 static volatile bool mouse_motion = false;
40
+static uint32_t last_health_check = 0;
37 41
 
38 42
 #ifdef PMW_IRQ_COUNTERS
39 43
 static uint64_t pmw_irq_count_all = 0;
@@ -48,16 +52,24 @@ static uint64_t pmw_irq_count_rest3 = 0;
48 52
 #endif // PMW_IRQ_COUNTERS
49 53
 
50 54
 void pmw_print_status(void) {
55
+    bool com = pmw_is_alive();
56
+    if (com) {
57
+        println("Communication to PMW3360 is working");
58
+    } else {
59
+        println("ERROR: can not communicate to PMW3360");
60
+    }
61
+
51 62
 #ifdef PMW_IRQ_COUNTERS
52
-    print("    pmw_irq_cnt_all = %llu", pmw_irq_count_all);
53
-    print(" pmw_irq_cnt_motion = %llu", pmw_irq_count_motion);
54
-    print("pmw_irq_cnt_no_move = %llu", pmw_irq_count_no_motion);
55
-    print("pmw_irq_cnt_surface = %llu", pmw_irq_count_on_surface);
56
-    print(" pmw_irq_cnt_lifted = %llu", pmw_irq_count_lifted);
57
-    print("    pmw_irq_cnt_run = %llu", pmw_irq_count_run);
58
-    print("  pmw_irq_cnt_rest1 = %llu", pmw_irq_count_rest1);
59
-    print("  pmw_irq_cnt_rest2 = %llu", pmw_irq_count_rest2);
60
-    print("  pmw_irq_cnt_rest3 = %llu", pmw_irq_count_rest3);
63
+    println("Interrupt statistics:");
64
+    println("    pmw_irq_cnt_all = %llu", pmw_irq_count_all);
65
+    println(" pmw_irq_cnt_motion = %llu", pmw_irq_count_motion);
66
+    println("pmw_irq_cnt_no_move = %llu", pmw_irq_count_no_motion);
67
+    println("pmw_irq_cnt_surface = %llu", pmw_irq_count_on_surface);
68
+    println(" pmw_irq_cnt_lifted = %llu", pmw_irq_count_lifted);
69
+    println("    pmw_irq_cnt_run = %llu", pmw_irq_count_run);
70
+    println("  pmw_irq_cnt_rest1 = %llu", pmw_irq_count_rest1);
71
+    println("  pmw_irq_cnt_rest2 = %llu", pmw_irq_count_rest2);
72
+    println("  pmw_irq_cnt_rest3 = %llu", pmw_irq_count_rest3);
61 73
 #endif // PMW_IRQ_COUNTERS
62 74
 }
63 75
 
@@ -314,21 +326,24 @@ uint8_t pmw_get_sensitivity(void) {
314 326
     return sense_y;
315 327
 }
316 328
 
329
+static void pmw_irq_start(void) {
330
+    gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, true);
331
+}
332
+
333
+static void pmw_irq_stop(void) {
334
+    gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, false);
335
+}
336
+
317 337
 static void pmw_irq_init(void) {
318 338
     // setup MOTION pin interrupt to handle reading data
319 339
     gpio_add_raw_irq_handler(PMW_MOTION_PIN, pmw_motion_irq);
320
-    gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, true);
340
+    pmw_irq_start();
321 341
     irq_set_enabled(IO_IRQ_BANK0, true);
322 342
 
323 343
     // make MOTION pin available to picotool
324 344
     bi_decl(bi_1pin_with_name(PMW_MOTION_PIN, "PMW3360 MOTION"));
325 345
 }
326 346
 
327
-static void pmw_irq_stop(void) {
328
-    gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, false);
329
-    irq_set_enabled(IO_IRQ_BANK0, false);
330
-}
331
-
332 347
 bool pmw_is_alive(void) {
333 348
     bool r = true;
334 349
     gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, false);
@@ -343,12 +358,84 @@ bool pmw_is_alive(void) {
343 358
     return r;
344 359
 }
345 360
 
361
+ssize_t pmw_frame_capture(uint8_t *buff, size_t buffsize) {
362
+    if ((buffsize < PMW_FRAME_CAPTURE_LEN) || (buff == NULL)) {
363
+        debug("invalid or too small buffer (%u < %u)", buffsize, PMW_FRAME_CAPTURE_LEN);
364
+        return -1;
365
+    }
366
+
367
+    pmw_irq_stop();
368
+
369
+    // write 0 to Rest_En bit of Config2 register to disable Rest mode
370
+    pmw_write_register(REG_CONFIG2, 0x00);
371
+
372
+    // write 0x83 to Frame_Capture register
373
+    pmw_write_register(REG_FRAME_CAPTURE, 0x83);
374
+
375
+    // write 0xC5 to Frame_Capture register
376
+    pmw_write_register(REG_FRAME_CAPTURE, 0xC5);
377
+
378
+    // wait for 20ms
379
+    busy_wait_ms(20);
380
+
381
+    // continue burst read from Raw_data_Burst register until all 1296 raw data are transferred
382
+    pmw_read_register_burst(REG_RAW_DATA_BURST, buff, PMW_FRAME_CAPTURE_LEN);
383
+
384
+    return PMW_FRAME_CAPTURE_LEN;
385
+}
386
+
387
+#define PMW_DATA_DUMP_SAMPLES 5000
388
+
389
+void pmw_dump_data(void) {
390
+    struct pmw_motion_report buff[PMW_DATA_DUMP_SAMPLES];
391
+
392
+    println("Will now capture %u data samples from PMW3360", PMW_DATA_DUMP_SAMPLES);
393
+    println("Move trackball to generate some data!");
394
+
395
+    pmw_irq_stop();
396
+
397
+    for (size_t i = 0; i < PMW_DATA_DUMP_SAMPLES; i++) {
398
+        // wait until MOTION pin is set
399
+        while (gpio_get(PMW_MOTION_PIN)) {
400
+            watchdog_update();
401
+        }
402
+
403
+        buff[i] = pmw_motion_read();
404
+    }
405
+
406
+    println();
407
+    println("time,motion,observation,delta_x,delta_y,squal,raw_sum,raw_max,raw_min,shutter");
408
+    for (size_t i = 0; i < PMW_DATA_DUMP_SAMPLES; i++) {
409
+        watchdog_update();
410
+
411
+        uint16_t delta_x_raw = buff[i].delta_x_l | (buff[i].delta_x_h << 8);
412
+        uint16_t delta_y_raw = buff[i].delta_y_l | (buff[i].delta_y_h << 8);
413
+        uint16_t shutter_raw = buff[i].shutter_lower | (buff[i].shutter_upper << 8);
414
+
415
+        print("%llu,", to_us_since_boot(get_absolute_time()));
416
+        print("%u,", buff[i].motion);
417
+        print("%u,", buff[i].observation);
418
+        print("%ld,", convert_two_complement(delta_x_raw));
419
+        print("%ld,", convert_two_complement(delta_y_raw));
420
+        print("%u,", buff[i].squal);
421
+        print("%u,", buff[i].raw_data_sum);
422
+        print("%u,", buff[i].maximum_raw_data);
423
+        print("%u,", buff[i].minimum_raw_data);
424
+        println("%u", shutter_raw);
425
+    }
426
+    println();
427
+
428
+    pmw_irq_start();
429
+}
430
+
346 431
 int pmw_init(void) {
432
+    // initializing takes a while (~160ms)
433
+    watchdog_update();
434
+
347 435
     pmw_irq_stop();
348 436
     pmw_spi_init();
349 437
 
350 438
     uint8_t srom_id = pmw_power_up();
351
-
352 439
     uint8_t prod_id = pmw_read_register(REG_PRODUCT_ID);
353 440
     uint8_t inv_prod_id = pmw_read_register(REG_INVERSE_PRODUCT_ID);
354 441
     uint16_t srom_checksum = pmw_srom_checksum();
@@ -368,13 +455,16 @@ int pmw_init(void) {
368 455
         return -1;
369 456
     }
370 457
 
371
-    if (srom_id != pmw_fw_id) {
372
-        debug("PMW3360 error: invalid SROM ID (0x%02X != 0x%02X)", srom_id, pmw_fw_id);
373
-        return -1;
374
-    }
458
+    if ((srom_id != pmw_fw_id) || (srom_checksum != pmw_fw_crc)) {
459
+        if (srom_id != pmw_fw_id) {
460
+            debug("PMW3360 error: invalid SROM ID (0x%02X != 0x%02X)", srom_id, pmw_fw_id);
461
+        }
462
+
463
+        if (srom_checksum != pmw_fw_crc) {
464
+            debug("PMW3360 error: invalid SROM CRC (0x%04X != 0x%04X)", srom_checksum, pmw_fw_crc);
465
+        }
375 466
 
376
-    if (srom_checksum != pmw_fw_crc) {
377
-        debug("PMW3360 error: invalid SROM CRC (0x%04X != 0x%04X)", srom_checksum, pmw_fw_crc);
467
+        debug("this may require a power-cycle to fix!");
378 468
         return -1;
379 469
     }
380 470
 
@@ -396,3 +486,14 @@ int pmw_init(void) {
396 486
 
397 487
     return 0;
398 488
 }
489
+
490
+void pmw_run(void) {
491
+    uint32_t now = to_ms_since_boot(get_absolute_time());
492
+    if (now >= (last_health_check + HEALTH_CHECK_INTERVAL_MS)) {
493
+        last_health_check = now;
494
+        if (!pmw_is_alive()) {
495
+            debug("PMW3360 is dead. resetting!");
496
+            reset_to_main();
497
+        }
498
+    }
499
+}

+ 13
- 0
firmware/src/util.c Целия файл

@@ -8,6 +8,7 @@
8 8
 #include "hardware/watchdog.h"
9 9
 
10 10
 #include "config.h"
11
+#include "log.h"
11 12
 #include "util.h"
12 13
 
13 14
 #define HEARTBEAT_INTERVAL_MS 500
@@ -64,3 +65,15 @@ void reset_to_main(void) {
64 65
         asm volatile("nop");
65 66
     }
66 67
 }
68
+
69
+void hexdump(uint8_t *buff, size_t len) {
70
+    for (size_t i = 0; i < len; i += 16) {
71
+        for (size_t j = 0; (j < 16) && ((i + j) < len); j++) {
72
+            print("0x%02X", buff[i + j]);
73
+            if ((j < 15) && ((i + j) < (len - 1))) {
74
+                print(" ");
75
+            }
76
+        }
77
+        println();
78
+    }
79
+}

+ 14
- 0
firmware/util/README.md Целия файл

@@ -0,0 +1,14 @@
1
+# RP2040 Trackball Firmware Utilities
2
+
3
+Some utilities to help with this project.
4
+
5
+## Frame Capture and Visualization
6
+
7
+The PMW3360 mouse sensor can do full captures of the raw 2D image seen by the chip.
8
+These can be grabbed from the firmware by opening the debug USB serial port and running the `pmwf` command.
9
+The output should be pasted into a textfile and can then be visualized using the included `visualize_frame.py` script.
10
+
11
+## Data Capture and Visualization
12
+
13
+The firmware can also grab a number of data samples from the sensor, by running the `pmwd` command.
14
+The output can then be visualized with `visualize_data.py`.

+ 43
- 0
firmware/util/visualize_data.py Целия файл

@@ -0,0 +1,43 @@
1
+#!/usr/bin/env python
2
+
3
+import matplotlib.pyplot as plt
4
+import numpy as np
5
+import sys
6
+import math
7
+
8
+if len(sys.argv) < 2:
9
+    print("Usage:")
10
+    print("    " + sys.argv[0] + " filename")
11
+    sys.exit(0)
12
+
13
+fig, axes = plt.subplots(6, 1, figsize=(5, 15))
14
+
15
+data = []
16
+lines_heading = []
17
+with open(sys.argv[1]) as f:
18
+    lines = f.readlines()
19
+    lines_heading = lines[0].split(',')
20
+    lines_data = lines[1:]
21
+    for line in lines_data:
22
+        nums = line.split(',')
23
+        line_data = []
24
+        for r in nums:
25
+            line_data.append(int(r))
26
+        data.append(line_data)
27
+
28
+start_time = data[0][0]
29
+for i in range(0, len(data)):
30
+    data[i][0] = (data[i][0] - start_time) / 1000.0 / 1000.0
31
+
32
+print("samples: " + str(len(data)))
33
+
34
+x = [ r[0] for r in data ]
35
+
36
+for n in range(3, 9):
37
+    y = [ r[n] for r in data ]
38
+    im = axes[n - 3].plot(x, y)
39
+    axes[n - 3].set_title(lines_heading[n])
40
+
41
+plt.suptitle(sys.argv[1], fontsize=18)
42
+plt.tight_layout()
43
+plt.show()

+ 47
- 0
firmware/util/visualize_frame.py Целия файл

@@ -0,0 +1,47 @@
1
+#!/usr/bin/env python
2
+
3
+import matplotlib.pyplot as plt
4
+import numpy as np
5
+import sys
6
+import math
7
+
8
+if len(sys.argv) < 2:
9
+    print("Usage:")
10
+    print("    " + sys.argv[0] + " filename [...]")
11
+    sys.exit(0)
12
+
13
+fig, axes = plt.subplots(1, len(sys.argv) - 1, figsize=(15, 5))
14
+
15
+# support one or multiple files
16
+if not isinstance(axes, np.ndarray):
17
+    axes = [axes]
18
+
19
+for n in range(0, len(sys.argv) - 1):
20
+    print("reading " + sys.argv[n + 1])
21
+
22
+    frame = []
23
+    with open(sys.argv[n + 1]) as f:
24
+        lines = f.readlines()
25
+        for line in lines:
26
+            nums = line.split()
27
+            for r in nums:
28
+                frame.append(int(r, 16))
29
+
30
+    print("frame length: " + str(len(frame)))
31
+    row_len = math.sqrt(len(frame))
32
+    print("row length: " + str(row_len))
33
+    row_len = int(row_len)
34
+
35
+    frame2d = []
36
+    for i in range(0, row_len):
37
+        row = []
38
+        for j in range(0, row_len):
39
+            row.append(frame[i * row_len + j])
40
+        frame2d.append(row)
41
+
42
+    im = axes[n].imshow(frame2d, vmin=0, vmax=0xFF, cmap='plasma')
43
+    axes[n].set_title(sys.argv[n + 1], fontsize=18)
44
+
45
+fig.colorbar(im, ax=axes, label='Value Range')
46
+plt.suptitle('Pan and Zoom on colorbar to adjust', fontsize=10)
47
+plt.show()

Loading…
Отказ
Запис