// Allows us to fill the first 8 CGRAM locations // with custom characters void display_createChar(uint8_t location, uint8_t charmap[]) { location &= 0x7; // we only have 8 locations 0-7 display_command(LCD_SETCGRAMADDR | (location << 3)); for (int i=0; i<8; i++) { display_write(charmap[i]); } }
static void ini_calc_string(Calc *calc) { strcpy(calc->value, " "); strcpy(calc->name, "Formula:"); calc->pos = strlen(calc->value); calc->col = (calc->pos + strlen(calc->name)) * DCURX; clr_command(); display_command(calc->name, calc->value, 2, 0); }
void display_setCursor(uint8_t col, uint8_t row) { int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; if ( row > _numlines ) { row = _numlines-1; // we count rows starting w/0 } display_command(LCD_SETDDRAMADDR | (col + row_offsets[row])); }
void display_begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { if (lines > 1) { _displayfunction |= LCD_2LINE; } _numlines = lines; _numcolumns = cols; _currline = 0; // for some 1 line displays you can select a 10 pixel high font if ((dotsize != 0) && (lines == 1)) { _displayfunction |= LCD_5x10DOTS; } // according to datasheet, we need at least 40ms after the input to the display rises above 2.7V _delay_us(50000); // Now we pull both RS and R/W low to begin display_commands LOW(_rs_pin); LOW(_enable_pin); //put the LCD into 4 bit mode if (! (_displayfunction & LCD_8BITMODE)) { // this is according to the hitachi HD44780 datasheet // figure 24, pg 46 // we start in 8bit mode, try to set 4 bit mode display_write4bits(0x03); _delay_us(4500); // wait min 4.1ms // second try display_write4bits(0x03); _delay_us(4500); // wait min 4.1ms // third go! display_write4bits(0x03); _delay_us(150); // finally, set to 8-bit interface display_write4bits(0x02); } else { // this is according to the hitachi HD44780 datasheet // page 45 figure 23 // Send function set display_command sequence display_command(LCD_FUNCTIONSET | _displayfunction); _delay_us(4500); // wait more than 4.1ms // second try display_command(LCD_FUNCTIONSET | _displayfunction); _delay_us(150); // third go display_command(LCD_FUNCTIONSET | _displayfunction); } // finally, set # lines, font size, etc. display_command(LCD_FUNCTIONSET | _displayfunction); // turn the display on with no cursor or blinking default _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; display_show(); // clear it off display_clear(); // Initialize to default text direction (for romance languages) _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; // set the entry mode display_command(LCD_ENTRYMODESET | _displaymode); }
// This will 'left justify' text from the cursor void display_noAutoscroll(void) { _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; display_command(LCD_ENTRYMODESET | _displaymode); }
// This is for text that flows Right to Left void display_rightToLeft(void) { _displaymode &= ~LCD_ENTRYLEFT; display_command(LCD_ENTRYMODESET | _displaymode); }
// This is for text that flows Left to Right void display_leftToRight(void) { _displaymode |= LCD_ENTRYLEFT; display_command(LCD_ENTRYMODESET | _displaymode); }
void display_home() { display_command(LCD_RETURNHOME); // set cursor position to zero _delay_us(2000); //command takes a long time according to datasheet }
// These display commands scroll the display without changing the RAM void display_scrollDisplayLeft(void) { display_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); }
void display_blink() { _displaycontrol |= LCD_BLINKON; display_command(LCD_DISPLAYCONTROL | _displaycontrol); }
// Turn on and off the blinking cursor void display_noBlink() { _displaycontrol &= ~LCD_BLINKON; display_command(LCD_DISPLAYCONTROL | _displaycontrol); }
void display_cursor() { _displaycontrol |= LCD_CURSORON; display_command(LCD_DISPLAYCONTROL | _displaycontrol); }
void display_show() { _displaycontrol |= LCD_DISPLAYON; display_command(LCD_DISPLAYCONTROL | _displaycontrol); }
// Turn the display on/off (quickly) void display_noDisplay() { _displaycontrol &= ~LCD_DISPLAYON; display_command(LCD_DISPLAYCONTROL | _displaycontrol); }
void command_process(char *command_line) { VideoCircularBuffer *vcb = &video_circular_buffer; Command *cmd; char command[64], args[128], buf[32], *path; int i, n; if (!command_line || *command_line == '\0') return; n = sscanf(command_line, "%63s %[^\n]", command, args); if (n < 1 || command[0] == '#') return; for (cmd = NULL, i = 0; i < COMMAND_SIZE; cmd = NULL, ++i) { cmd = &commands[i]; if (!strcmp(command, cmd->name)) { if (cmd->n_args != n - 1) { log_printf("Wrong number of args for command: %s\n", command); return; } break; } } if (!cmd) { if ( !config_set_option(command, args, FALSE) && !mmalcam_config_parameter_set(command, args, TRUE) ) log_printf("Bad command: [%s] [%s]\n", command, args); return; } if (cmd->code != display_cmd) log_printf("command_process: %s\n", command_line); if (cmd->code < display_cmd && !display_is_default()) { display_set_default(); return; } switch (cmd->code) { case record: pthread_mutex_lock(&vcb->mutex); if (config_boolean_value(args) == TRUE) { if (vcb->pause) vcb->pause = FALSE; else { if (vcb->state == VCB_STATE_MOTION_RECORD) video_record_stop(vcb); video_record_start(vcb, VCB_STATE_MANUAL_RECORD_START); } } else video_record_stop(vcb); pthread_mutex_unlock(&vcb->mutex); break; case record_pause: /* Can pause manual record only. Because of event_gap/capture | times, I'm not even sure what it would mean to pause a | motion record. */ pthread_mutex_lock(&vcb->mutex); if (vcb->state == VCB_STATE_MANUAL_RECORD) vcb->pause = vcb->pause ? FALSE : TRUE; else vcb->pause = FALSE; pthread_mutex_unlock(&vcb->mutex); break; case still: snprintf(buf, sizeof(buf), "%d", pikrellcam.still_sequence); path = media_pathname(pikrellcam.still_dir, pikrellcam.still_filename, 'N', buf, '\0', NULL); pikrellcam.still_sequence += 1; still_capture(path); free(path); break; case tl_start: if ((n = atoi(args)) < 1) n = 0; time_lapse.activated = TRUE; time_lapse.on_hold = FALSE; if (!time_lapse.event && n > 0) { time_lapse.sequence = 0; ++time_lapse.series; time_lapse.event = event_add("timelapse", pikrellcam.t_now, n, timelapse_capture, NULL); } else if (n > 0) /* Change the period */ { time_lapse.event->time += (n - time_lapse.period); time_lapse.event->period = n; } if (n > 0) time_lapse.period = n; /* n == 0 just sets on_hold FALSE */ config_timelapse_save_status(); break; case tl_hold: config_set_boolean(&time_lapse.on_hold, args); config_timelapse_save_status(); break; case tl_end: if (time_lapse.activated) { event_remove(time_lapse.event); time_lapse.event = NULL; time_lapse.activated = FALSE; time_lapse.on_hold = FALSE; config_timelapse_save_status(); exec_no_wait(pikrellcam.on_timelapse_end_cmd, NULL); } break; case tl_inform_convert: if (!strcmp(args, "done")) { event_remove(time_lapse.inform_event); dup_string(&time_lapse.convert_name, ""); time_lapse.convert_size = 0; } else { dup_string(&time_lapse.convert_name, args); time_lapse.inform_event = event_add("tl_inform_convert", pikrellcam.t_now, 5, timelapse_inform_convert, NULL); } break; case tl_show_status: config_set_boolean(&time_lapse.show_status, args); break; case display_cmd: display_command(args); break; case motion_cmd: motion_command(args); break; case motion_enable: n = motion_frame.motion_enable; config_set_boolean(&motion_frame.motion_enable, args); if (n && !motion_frame.motion_enable) { pthread_mutex_lock(&vcb->mutex); if (vcb->state == VCB_STATE_MOTION_RECORD) video_record_stop(vcb); pthread_mutex_unlock(&vcb->mutex); } break; case save_config: config_save(pikrellcam.config_file); break; case quit: config_timelapse_save_status(); if (pikrellcam.config_modified) config_save(pikrellcam.config_file); display_quit(); exit(0); break; default: log_printf("command in table with no action!\n"); break; } }
void display_scrollDisplayRight(void) { display_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); }
void display_init() { i2c_master_setup(); // goes through the reset procedure display_command(0xAE); // turn off display display_command(0xA8); // set the multiplex ratio (how many rows are updated per oled driver clock) to the number of rows in the display display_command(HEIGHT-1); // the multiplex ratio set is the value sent + 1, so subtract 1 // we will always write the full display on a single update. display_command(0x20); // set address mode display_command(0x00); // horizontal address mode display_command(0x21); // set column address display_command(0x00); // start at 0 display_command(0xFF); // end at 127 // with this address mode, the address will go through all the pixels and then return to the start, // hence we never need to set the address again display_command(0x8d); // charge pump display_command(0x14); // turn charge pump on (creates the ~7 Volts needed to light pixels) display_command(0xAF); // turn on the display video_buffer[0] = 0x40; // co = 0, dc =1, allows us to send data directly from video buffer, //0x40 is the "next bytes have data" byte }
void display_clear() { display_command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero _delay_us(2000); //command takes a long time according to datasheet }