#ifndef SKIP_GPIO #include #include #include #endif // SKIP_GPIO #include #include #include #include #include #include "multiplexer.h" int mem_fd; void *gpio_map; volatile unsigned *gpio; // // Set up a memory regions to access GPIO // int multiplexer_setup_root() { #ifndef SKIP_GPIO /* open /dev/mem */ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { perror("can't open /dev/mem"); return EXIT_FAILURE; } /* mmap GPIO */ gpio_map = mmap( NULL, //Any adddress in our space will do BLOCK_SIZE, //Map length PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory MAP_SHARED, //Shared with other processes mem_fd, //File to map GPIO_BASE //Offset to GPIO peripheral ); close(mem_fd); //No need to keep mem_fd open after mmap if (gpio_map == MAP_FAILED) { perror("mmap error"); return EXIT_FAILURE; } // Always use volatile pointer! gpio = (volatile unsigned *)gpio_map; #endif // !SKIP_GPIO } // multiplexer_setup_root // // Shift the bits provided in content into the display // void *put_on_display(void *param) { t_display_data *display_data = param; int line, column; #ifndef SKIP_GPIO struct timespec start_time, stop_time; #endif // !SKIP_GPIO while (display_data -> keep_running) { #ifdef SKIP_GPIO usleep(10000); #endif // SKIP_GPIO display_data -> is_buf = display_data -> should_buf; if (!display_data -> should_be_on) { if (display_data -> is_on) { turn_off_display(); memset(display_data -> buf, 0, sizeof(display_data -> buf)); display_data -> is_on = 0; } sleep(1); continue; } display_data -> is_on = 1; #ifdef SKIP_GPIO #ifndef SILENT printf("=\n"); #endif // !SILENT for (line=0; line<7; line++) { for (column=0; column<40; column++) { #ifndef SILENT if (display_data -> buf[display_data -> is_buf][column] & (0x01 << line)) printf("X"); else printf(" "); #endif // !SILENT #else // SKIP_GPIO for (line=6; line>=0; line--) { GPIO_CLR = 1< keep_running = 0; perror("clock_gettime failed"); break; } for (column=0; column<8; column++) { GPIO_ALTER(column + line == 7) = 1<=0; column--) { GPIO_ALTER(display_data -> buf[display_data -> is_buf][column] & (0x01 << line)) = 1< keep_running = 0; perror("clock_gettime failed"); break; } // adjust tpic_settle_time_iterator if ((tpic_settle_time_iterator > 0) && (stop_time.tv_sec - start_time.tv_sec + (stop_time.tv_nsec - start_time.tv_nsec) / 1000000000. > 0.0003)) { // fprintf(stderr, "%d -> ", tpic_settle_time_iterator); tpic_settle_time_iterator--; // fprintf(stderr, "%d\n", tpic_settle_time_iterator); } else if ((tpic_settle_time_iterator < 200000) && (stop_time.tv_sec - start_time.tv_sec + (stop_time.tv_nsec - start_time.tv_nsec) / 1000000000. < 0.0001)) { // fprintf(stderr, "%d -> ", tpic_settle_time_iterator); tpic_settle_time_iterator++; tpic_settle_time_iterator *= 2; // fprintf(stderr, "%d\n", tpic_settle_time_iterator); } // wait until start_time + 1ms int wait = (start_time.tv_sec - stop_time.tv_sec) * 1000000 + (start_time.tv_nsec - stop_time.tv_nsec) / 1000 + 1000; if (wait > 0) usleep(wait); GPIO_SET = 1< keep_running) { if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time) != 0) { scroll_data -> keep_running = 0; perror("clock_gettime failed"); break; } if ((scroll_data -> shine_until != 0) && (scroll_data -> shine_until < time(NULL))) { // turn off display display_data . should_be_on = 0; column = 0; } else { // turn on display display_data . should_be_on = 1; } if (scroll_data -> update) { if ((buf[is_buf] . len != scroll_data -> input_len) || (memcmp(&buf[is_buf] . buf[buf[is_buf] . start], scroll_data -> input, scroll_data -> input_len) != 0)) { is_buf = (is_buf + 1) % 2; // copy the currently visible, old content memcpy(buf[is_buf] . buf, &buf[(is_buf + 1) % 2] . buf[column + 1], 39); buf[is_buf] . start = 39; // set the length of the new content buf[is_buf] . len = scroll_data -> input_len; // copy the new content from input for (int i=0; i<2; i++) memcpy( &buf[is_buf] . buf[39 + i * buf[is_buf] . len], scroll_data -> input, buf[is_buf] . len ); column = 0; } // clear update flag scroll_data -> update = 0; } if (display_data . should_be_on != 0) { for (int i=0; i<40; i++) display_data . buf[(display_data . should_buf + 1) % 3][i] = buf[is_buf] . buf[column + i]; column++; if (buf[is_buf] . len > 0) while (column >= buf[is_buf] . start + buf[is_buf] . len) column -= buf[is_buf] . len; } if (clock_gettime(CLOCK_MONOTONIC_RAW, &stop_time) != 0) { scroll_data -> keep_running = 0; perror("clock_gettime failed"); break; } // wait until start_time + 50ms int wait = (start_time.tv_sec - stop_time.tv_sec) * 1000000 + (start_time.tv_nsec - stop_time.tv_nsec) / 1000 + 25000; if (wait > 0) usleep(wait); if (display_data . should_be_on != 0) display_data . should_buf = (display_data . should_buf + 1) % 3; } display_data . keep_running = 0; pthread_join(display_data . thread_id, NULL); } // scroll_it void multiplexer_setup_non_root(t_display_data *display_data) { #ifndef SKIP_GPIO // must use INP_GPIO before we can use OUT_GPIO INP_GPIO(SER_DAT_PIN); OUT_GPIO(SER_DAT_PIN); INP_GPIO(SER_CLK_PIN); OUT_GPIO(SER_CLK_PIN); INP_GPIO(GATE_PIN); OUT_GPIO(GATE_PIN); INP_GPIO(PAR_CLK_PIN); OUT_GPIO(PAR_CLK_PIN); INP_GPIO(SENSE_PIN); // enable pull-up on SENSE_PIN /** adopted from wiringPi's wiringPi/wiringPi.c lines 1507-1511 **/ *(gpio + GPPUD) = 2; // bit 0: pull down; bit 1: pull up usleep(5); *(gpio + gpioToPUDCLK[SENSE_PIN]) = 1 << (SENSE_PIN & 31); usleep(5); *(gpio + GPPUD) = 0; usleep(5); *(gpio + gpioToPUDCLK[SENSE_PIN]) = 0; usleep(5); /** end of adoption **/ #endif // !SKIP_GPIO for (int i=0; i<3; i++) memset(display_data -> buf[i],0,40); display_data -> is_buf = 0; display_data -> should_buf = 0; display_data -> keep_running = 1; display_data -> is_on = 1; display_data -> should_be_on = 1; pthread_create(&display_data -> thread_id, NULL, put_on_display, display_data); return; } // multiplexer_setup_non_root void multiplexer_setup_scroll(t_scroll_data *scroll_data) { scroll_data -> update = 0; scroll_data -> keep_running = 1; scroll_data -> shine_until = 0; pthread_create(&scroll_data -> thread_id, NULL, scroll_it, scroll_data); return; } // multiplexer_setup_scroll void turn_off_display() { #ifndef SKIP_GPIO GPIO_SET = 1<