All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ociweb.iot.grove.oled.OLED_128x64_Transducer Maven / Gradle / Ivy

Go to download

FogLight is a lightweight runtime that enables makers of all ages and skill levels to create highly performant apps for embedded devices like Raspberry Pi's.

The newest version!
package com.ociweb.iot.grove.oled;

import com.ociweb.iot.maker.IODeviceTransducer;

import static com.ociweb.iot.grove.oled.Grove_OLED_128x64_Constants.*;
import static com.ociweb.iot.grove.oled.Grove_OLED_128x64_Constants.Direction.*;
import static com.ociweb.iot.grove.oled.Grove_OLED_128x64_Constants.Orientation.*;

import com.ociweb.gl.api.transducer.StartupListenerTransducer;
import com.ociweb.iot.grove.oled.Grove_OLED_128x64_Constants.Direction;
import com.ociweb.iot.grove.oled.Grove_OLED_128x64_Constants.Orientation;
import com.ociweb.iot.maker.FogCommandChannel;
import com.ociweb.iot.maker.image.FogBitmap;
import com.ociweb.iot.maker.image.FogBitmapLayout;
import com.ociweb.iot.maker.image.FogColorSpace;

/**
 * IODeviceTransducer object that holds on to the FogCommandChannel, data_output array, and cmd_output array.
 * This class also contains all of the methods that can communicate with the OLED 128x64 display.
 * @author Ray Lo, Nathan Tippy
 *
 */
public class OLED_128x64_Transducer extends BinaryOLED implements IODeviceTransducer, StartupListenerTransducer{
	/**
	 * Constructs an instance of OLED_128x64 that holds on to the {@link FogCommandChannel} passed in.
	 * @param ch FogCommandChannel used for the i2c write.
	 */

	public OLED_128x64_Transducer(FogCommandChannel ch){
		super(ch, new int[1024], new int[32], OLEDADDRESS);
		ch.ensureI2CWriting(100, BATCH_SIZE);
		//the most amount of data we can ever send at once as this is one entire frame worth of data
		//the static Grove_OLED_128x64 class requires that we send out no more than 10 bytes at once. 32 bytes are allocated for safety.
	}

	/**
	 * Flashes the display screen off and then on and ensures that the inverse_display and scrolling functions
	 *  are turned off. The display is left in the Page mode afterwards.
	 * @return true if the commands were sent, returns false if any single command was not sent.
	 */
	@Override
	protected boolean init(){
		cmd_out[0] = PUT_DISPLAY_TO_SLEEP;
		cmd_out[1] = CHARGE_PUMP_SETTING;
		cmd_out[2] = CHARGE_PUMP_ON;
        cmd_out[3] = WAKE_DISPLAY;
		cmd_out[4] = TURN_OFF_INVERSE_DISPLAY;
		cmd_out[5] = DEACTIVATE_SCROLL;
		cmd_out[6] = SET_MEMORY;
		cmd_out[7] = 0x02;
		cmd_out[8] = SET_DISPLAY_OFFSET;
		cmd_out[9] = 0x00;
		return sendCommands(0, 10);
	}

	@Override
	public FogBitmapLayout newBmpLayout() {
		FogBitmapLayout bmpLayout = new FogBitmapLayout(FogColorSpace.gray);
		bmpLayout.setComponentDepth((byte) 1);
		bmpLayout.setWidth(colCount);
		bmpLayout.setHeight(rowCount);
		return bmpLayout;
	}

	@Override
	public boolean display(FogBitmap bmp) {
		return false;
	}

	/**
	 * Sets the contrast (olso refered to as brightness) of the display.
	 * @param contrast is a value ranging from 0 to 255. A bit-mask is enforced so that only the lowest 8 bits of the supplied integer will matter.
	 * @return true if the command byte and the contrast byte were sent, false otherwise.
	 */
	@Override
	public boolean setContrast(int contrast){
		cmd_out[0] = SET_CONTRAST_CONTROL;
		cmd_out[1] = contrast & 0xFF;
		return sendCommands(0, 2);
	}

	/**
	 * Sets the display in page mode, necessary for {@link #setTextRowCol(int,int)}, {@link #printCharSequence(CharSequence)} . 
	 * @return true if all three bytes needed were sent, false otherwise.
	 * @see SSD1308.pdf
	 *for information on page mode.
	 */
	public boolean setPageMode(){		
		cmd_out[0] = SET_MEMORY;
		cmd_out[1] = 0x02;
		return sendCommands(0, 2);
	}

	/**
	 * Sets the display in horizontal mode, necessary for  {@link #display(int[][])}
	 * Note that both {drawBitmap(FogCommandChannel, int[], int[])} and {displayImage(int[][])} already automatically set the display in
	 * horizontal mode.
	 * @return true if all three bytes needed were sent, false otherwise.
	 * @see SSD1308.pdf
	 * for information on horizontal mode. 
	 */

	@Override
	public boolean setHorizontalMode(){
		cmd_out[0] = SET_MEMORY;
		cmd_out[1] = 0x00;
		return sendCommands(0, 2);
	}

	/**
	 * Sets the display in vertical mode.
	 * @return true if all three bytes needed were sent, false otherwise. 
	 * @see SSD1308.pdf
	 * for information on vertical mode.
	 */

	@Override
	public boolean setVerticalMode(){
		cmd_out[0] = SET_MEMORY;
		cmd_out[1] = 0x01;
		return sendCommands(0, 2);
	}

	/**
	 * Turns on the inverse feature which switches all black pixels with white pixels and vice versa.
	 * @return true if all two necessary bytes were sent, false otherwise.
	 */
	@Override
	public boolean inverseOn(){
		return sendCommand(TURN_ON_INVERSE_DISPLAY);
	}

	/**
	 * Turns off the inverse feature which switches all black pixels with white pixels and vice versa.
	 * @return true if all two necessary bytes were sent, false otherwise.
	 */
	@Override
	public boolean inverseOff(){
		return sendCommand(TURN_OFF_INVERSE_DISPLAY);
	}

	/**
	 * Activates the scroll feature.
	 * NOTE: One of the four set-up methods ({setUpRightContinuousVerticalHorizontalScroll(ScrollSpeed, int, int, int)},
	 * {setUpLeftContinuousVerticalHorizontalScroll(ScrollSpeed, int, int, int)}, {setUpRightContinuousHorizontalScroll(ScrollSpeed, int, int)},
	 * and {setUpLeftContinuousVerticalHorizontalScroll(ScrollSpeed, int, int, int)}) needs to be invoked first.

	 * @return true if all two necessary bytes were sent, false otherwise.
	 * @see SSD1308.pdf
	 * for information on scrolling.
	 */
	@Override
	public boolean activateScroll(){
		return sendCommand(ACTIVATE_SCROLL);
	}

	/**
	 * Deactivates the scroll feature.
	 * @return true if all two necessary bytes were sent, false otherwise.
	 * @see SSD1308.pdf
	 * for information on scrolling.
	 */
	@Override
	public boolean deactivateScroll(){
		return sendCommand(DEACTIVATE_SCROLL);
	}

	/**
	 * Prints CharSequence at the specified row and column
	 * @param s the CharSequence to be printed
	 * @param row the row
	 * @param col the column
	 * @return true if the commands were sent, false otherwise.
	 */
	@Override
	public boolean printCharSequenceAt(CharSequence s,int row, int col){
		return setTextRowCol(row,col) && printCharSequence(s);
	}


	/**
	 * Prints CharSequence at the specified row and column
	 * @param s the CharSequence to be printed
	 * @return true if the commands were sent, false otherwise.
	 */
	@Override
	public boolean printCharSequence(CharSequence s){
		encodeCharSequence(s);
		return sendData(0, s.length()*8);
	}

	/**
	 * Pritns the charSequence with custom fonts.
	 * @param s
	 * @param customFonts must be an n by 8 array, where fonts for n characters are defined. Each row of the array defines a character.
	 * @param offset can be supplied depending on which fonts are defined. i.e. if the customFonts array's first row defines the [space] character,
	 * it wold be useful to set offset to be 32, which is the decimal ASCII value of [space]. That way, callers of this function can supply the chars directly without
	 * handling the offset themselves.
	 * @return true if the data was sent; false otherwise.
	 */
	public boolean printCharSequence(CharSequence s, int[][] customFonts, int offset){
		encodeCharSequence(s, 0,customFonts,offset);
		return sendData(0, s.length()*8);

	}

	private boolean encodeChar(char c){
		return encodeChar(c, 0);
	}

	/**
	 * Modifies the data_out array to have necessary raw bytes to print a char
	 * @param c the char to be encoded
	 * @param start is the starting index within data_out where the char should be encoded (8 bytes, since the chars are 8x8)
	 * @return true
	 */
	private boolean encodeChar(char c, int start){
		if (c > 127 || c < 32){
			c = ' ';
		}
		int counter = 0;
		for (int i = start; i < start + 8; i++){
			data_out[i] = BASIC_FONT[c-32][counter++];
		}
		return true;
	}


	private boolean encodeChar(char c, int[][] customFontArray){
		return encodeChar(c,0,customFontArray,0);
	}

	private boolean encodeChar(char c, int[][] customFontArray, int charOffset){
		return encodeChar(c,0,customFontArray, charOffset);
	}

	private boolean encodeChar(char c, int start, int[][] customFontArray, int charOffset){
		if (c > charOffset + customFontArray.length || c < charOffset){
			//'c' has no defined font in the custom array supplied.
		}
		int counter = 0;
		for (int i = start; i < start + 8; i++){
			data_out[i] = customFontArray[c-charOffset][counter++];
		}
		return true;

	}

	private boolean encodeCharSequence(CharSequence s, int start, int[][] customFontArray, int offset){
		for (int i = start; i < start + s.length(); i++){
			if (encodeChar(s.charAt(i), i*8, customFontArray, offset)){	
			} else {
				return false;
			}
		}
		return true;
	}

	/**
	 * Modifies the data_out array to have necessary raw bytes to print a char, starting at index 0.
	 * @param s the char to be encoded
	 * @return true if all of the chars given have valid fonts.
	 */
	private boolean encodeCharSequence(CharSequence s){
		return encodeCharSequence(s, 0);
	}

	/**
	 * Modifies the data_out array to have necessary raw bytes to print a char
	 * @param s the char to be encoded
	 * @param start is the starting index within data_out where the CharSequence should be encoded.
	 * @return true if all of the chars given have valid fonts.
	 */
	private boolean encodeCharSequence(CharSequence s, int start){
		for (int i = start; i < start + s.length(); i++){
			if (encodeChar(s.charAt(i), i*8)){	
			} else {
				return false;
			}
		}
		return true;
	}

	/**
	 * Sets the display's row and col in terms of a grid of 8x8 characters.
	 * NOTE: this method requires that the display be in Page mode.
	 * @param row
	 * @param col
	 * @return true if the data was sent, false otherwise.
	 */
	@Override
	public boolean setTextRowCol( int row, int col){ //only works in Page Mode
		//bit-mask because x and y can only be within a certain range (0-7)

		cmd_out[0] = ROW_START_ADDRESS_PAGE_MODE + (row & 0x07);
		cmd_out[1] = LOWER_COL_START_ADDRESS_PAGE_MODE + (8*col & 0x0F);
		cmd_out[2] = HIGHER_COL_START_ADDRESS_PAGE_MODE + ((8*col >> 4) & 0x0F);


		return sendCommands(0, 3);
	}


	/**
	 * Set the display in page mode and then sets the display's row and col in terms of a grid of 8x8 characters.
	 * NOTE: this method requires that the display be in Page mode.
	 * @param row
	 * @param col
	 * @return true if the commands and data were sent, false otherwise.
	 */
	public boolean setPageModeAndTextRowCol(int row, int col){
		return setPageMode() && setTextRowCol(row,col);

	}

	public boolean setDisplayStartLine(int startLine){
		cmd_out[0] =  DISPLAY_START_LINE;
		cmd_out[1] = startLine & 0x3F;
		return sendCommands(0,2);
	}

	public boolean remapSegment(boolean isRemapped){
		int remap_cmd = MAP_ADDRESS_0_TO_SEG0;
		if (isRemapped){
			remap_cmd = MAP_ADDRESS_127_TO_SEG0;
		}
		return sendCommand(remap_cmd);
	}


	/**
	 * Switches the display to page mode to print spaces all across the screen.
	 * @return true if the commands were sent, false otherwise.
	 */

	@Override
	public boolean clear(){
		if (setPageMode()){

		} else {
			return false;
		}

		for (int row = 0; row < 8; row++){
			setTextRowCol(row, 0);
			if (sendData(EMPTY_ROW)){
			} else {
				return false;
			}
		}
		return true;
	}
	
	
	 /**
	  * Turns the display off before clearing. Turns the display back on after clearing.
	  * @return true if the commands were sent; false otherwise.
	  */
	@Override
	public  boolean cleanClear(){
		if (sendCommand(PUT_DISPLAY_TO_SLEEP)
				&& clear() 
				&& sendCommand(WAKE_DISPLAY))
		{
			ch.i2cFlushBatch();
			return true;
		}
		ch.i2cFlushBatch();		
		return false;
	}

	public  boolean setMultiplexRatio(int mux_ratio){
		cmd_out[0] = SET_MUX_RATIO;
		cmd_out[1] = mux_ratio & 0x3F;
		return sendCommands( 0,2);
	}

	public boolean setClockDivRatioAndOscFreq(int clock_div_ratio, int osc_freq){
		cmd_out[0] = SET_CLOCK_DIV_RATIO;
		cmd_out[1] = (clock_div_ratio & 0x0F) | (osc_freq << 4 & 0xF0);
		return sendCommands( 0,2);

	}
	public boolean setVerticalOffset(int offset){
		cmd_out[0] = SET_DISPLAY_OFFSET;
		cmd_out[1] = offset & 0x3F;
		return sendCommands( 0,2);
	}

	public boolean setUpRightContinuousHorizontalScroll(ScrollSpeed speed, int startPage, int endPage){
		return setUpContinuousHorizontalScroll( speed, startPage, endPage, Right);
	}
	public boolean setUpLeftContinuousHorizontalScroll(ScrollSpeed speed, int startPage, int endPage){
		return setUpContinuousHorizontalScroll( speed, startPage, endPage, Left);
	}

	public boolean setUpRightContinuousVerticalHorizontalScroll(ScrollSpeed speed, int startPage, 
			int endPage, int offset){
		return setUpContinuousVerticalHorizontalScroll( speed, startPage, endPage, offset, Vertical_Right);
	}

	public boolean setUpLeftContinuousVerticalHorizontalScroll(ScrollSpeed speed, int startPage, 
			int endPage, int offset){
		return setUpContinuousVerticalHorizontalScroll(speed, startPage, endPage, offset, Vertical_Left);
	}


	private boolean setUpContinuousHorizontalScroll(ScrollSpeed speed, int startPage, int endPage, 
			Direction dir){	
		generateHorizontalScrollComamnds(speed,startPage,endPage,dir);
		return sendCommands(0,7);
	}

	private void generateHorizontalScrollComamnds(ScrollSpeed speed, int startPage, int endPage, 
			Direction dir){

		cmd_out[0] = dir == Right? SET_RIGHT_HOR_SCROLL:SET_LEFT_HOR_SCROLL;
		cmd_out[1] = 0x00; //dummy byte as required
		cmd_out[2] = startPage & 0x07;
		cmd_out[3] =speed.COMMAND;
		cmd_out[4] =endPage & 0x07;
		cmd_out[5] = 0xFF; // dummy byte as required
		cmd_out[6] = 0x00; // dummy byte as required		
	}

	private boolean setUpContinuousVerticalHorizontalScroll(ScrollSpeed speed, int startPage, int endPage,
			int offset, Orientation dir){
		generateVerticalHorizontalScrollComamnds(speed,startPage,endPage,offset,dir);
		return sendCommands(0,6);

	}

	private void generateVerticalHorizontalScrollComamnds(ScrollSpeed speed, int startPage, int endPage, 
			int offset, Orientation ori){

		cmd_out[0] = ori == Vertical_Right? SET_VER_AND_RIGHT_HOR_SCROLL:SET_VER_AND_LEFT_HOR_SCROLL;
		cmd_out[1] = 0x00; //dummy byte as required
		cmd_out[2] = startPage & 0x07;
		cmd_out[3] =speed.COMMAND;
		cmd_out[4] =endPage & 0x07;
		cmd_out[5] = offset & 0x1F;
	}

	/**
	 * NOTE: this method leaves the display in horizontal mode

	 * @param map
	 * @return true if the i2c commands were succesfully sent, false otherwise
	 */


	private boolean drawBitmapInHorizontalMode(int[] map){
		if (!setHorizontalMode()){
			return false;
		}
		return sendData(map);
	}
	
	private boolean drawBitmap(int[] map){
		return drawBitmapInPageMode(map);
	}
	


	/**
	 * NOTE: drawing in page mode instead of horizontal mode sends 16 extra bytes per reflash compared to drawing
	 * in horizontal mode as we need to reset textRowCol everytime we reach a new page. It may be preferable to use
	 * drawing in page mode however, as it eliminates the need to switch between page mode and horizontal mode when doing
	 * both drawing and CharSequence printing.
	 * @return true
	 */

	public  boolean drawBitmapInPageMode (int[] map){
		for (int page = 0; page <8; page++){
			if (! setTextRowCol(page,0)){
				return false;
			}
			int startingPoint = page*128;

			if (!sendData(map, startingPoint, 128)){
				return false;
			}

		}
		return true;
	}

	@Override
	public boolean display(int[][] raw_image){
		return display(raw_image,1);
	}

	@Override
	public boolean display(int[][] raw_image, int pixelDepth) {
		int counter = 0;
		int pageLimit = rowCount >> 3;
		for (int page = 0; page < pageLimit; page++){
			for (int seg = 0; seg < colCount; seg++){
				data_out[counter] = parseColByte(raw_image, page*8, seg, 1);
				counter++;
			}
		}
		return drawBitmap(data_out);
	
	}

	private static int parseColByte(int[][]raw_image, int row, int col, int pixelDepth){
		int ret = 0;
		for (int i = 0; i < 8; i ++){
			ret = ret | (raw_image[row+i][col] & (0x01 << pixelDepth - 1)) << i;
		}
		return ret;
	}

	@Override
	public boolean displayOn() {	
		return sendCommand(WAKE_DISPLAY);
	}

	@Override
	public boolean displayOff() {
		return sendCommand(PUT_DISPLAY_TO_SLEEP);
	}

	@Override
	public boolean setUpScroll() {
		return false;
	}

	@Override
	public void startup() {
		init(); 
		clear();	
	}
}






© 2015 - 2025 Weber Informatics LLC | Privacy Policy