2018-02-11 19:34:47 +01:00
package gpio
import (
"math"
"strings"
"gobot.io/x/gobot"
)
2023-02-14 13:57:24 +01:00
// Colors of the display
2018-02-11 19:34:47 +01:00
const (
TM1638None = iota
TM1638Red
TM1638Green
)
2023-02-14 13:57:24 +01:00
// Commands of the driver
2018-02-11 19:34:47 +01:00
const (
TM1638DataCmd = 0x40
TM1638DispCtrl = 0x80
TM1638AddrCmd = 0xC0
TM1638WriteDisp = 0x00
TM1638ReadKeys = 0x02
TM1638FixedAddr = 0x04
)
// TM1638Driver is the gobot driver for modules based on the TM1638, which has 8 7-segment displays, 8 LEDs and 8 buttons
// Buttons are not supported
//
// Datasheet EN: https://retrocip.cz/files/tm1638.pdf
// Datasheet CN: http://www.datasheetspdf.com/pdf/775356/TitanMicro/TM1638/1
//
// Ported from the Arduino driver https://github.com/rjbatista/tm1638-library
type TM1638Driver struct {
2023-02-14 13:57:24 +01:00
pinClock * DirectPinDriver
2018-02-11 19:34:47 +01:00
pinData * DirectPinDriver
pinStrobe * DirectPinDriver
fonts map [ string ] byte
name string
connection gobot . Connection
gobot . Commander
}
// NewTM1638Driver return a new TM1638Driver given a gobot.Connection and the clock, data and strobe pins
func NewTM1638Driver ( a gobot . Connection , clockPin string , dataPin string , strobePin string ) * TM1638Driver {
t := & TM1638Driver {
name : gobot . DefaultName ( "TM1638" ) ,
2023-02-14 13:57:24 +01:00
pinClock : NewDirectPinDriver ( a , clockPin ) ,
2018-02-11 19:34:47 +01:00
pinData : NewDirectPinDriver ( a , dataPin ) ,
pinStrobe : NewDirectPinDriver ( a , strobePin ) ,
fonts : NewTM1638Fonts ( ) ,
connection : a ,
Commander : gobot . NewCommander ( ) ,
}
/* TODO : Add commands */
return t
}
// Start initializes the tm1638, it uses a SPI-like communication protocol
func ( t * TM1638Driver ) Start ( ) ( err error ) {
t . pinStrobe . On ( )
2018-02-24 11:31:53 +01:00
t . pinClock . On ( )
2018-02-11 19:34:47 +01:00
t . sendCommand ( TM1638DataCmd )
t . sendCommand ( TM1638DispCtrl | 8 | 7 )
t . pinStrobe . Off ( )
t . send ( TM1638AddrCmd )
for i := 0 ; i < 16 ; i ++ {
t . send ( TM1638WriteDisp )
}
t . pinStrobe . On ( )
return
}
// Halt implements the Driver interface
func ( t * TM1638Driver ) Halt ( ) ( err error ) { return }
// Name returns the TM1638Drivers name
func ( t * TM1638Driver ) Name ( ) string { return t . name }
// SetName sets the TM1638Drivers name
func ( t * TM1638Driver ) SetName ( n string ) { t . name = n }
// Connection returns the TM1638Driver Connection
func ( t * TM1638Driver ) Connection ( ) gobot . Connection {
return t . connection
}
// sendCommand is an auxiliary function to send commands to the TM1638 module
func ( t * TM1638Driver ) sendCommand ( cmd byte ) {
t . pinStrobe . Off ( )
t . send ( cmd )
t . pinStrobe . On ( )
}
// send writes data on the module
func ( t * TM1638Driver ) send ( data byte ) {
for i := 0 ; i < 8 ; i ++ {
2018-02-24 11:31:53 +01:00
t . pinClock . Off ( )
2018-02-11 19:34:47 +01:00
if ( data & 1 ) > 0 {
t . pinData . On ( )
} else {
t . pinData . Off ( )
}
data >>= 1
2018-02-24 11:31:53 +01:00
t . pinClock . On ( )
2018-02-11 19:34:47 +01:00
}
}
// sendData is an auxiliary function to send data to the TM1638 module
func ( t * TM1638Driver ) sendData ( address byte , data byte ) {
t . sendCommand ( TM1638DataCmd | TM1638FixedAddr )
t . pinStrobe . Off ( )
t . send ( TM1638AddrCmd | address )
t . send ( data )
t . pinStrobe . On ( )
}
// SetLED changes the color (TM1638None, TM1638Red, TM1638Green) of the specific LED
func ( t * TM1638Driver ) SetLED ( color byte , pos byte ) {
if pos > 7 {
return
}
t . sendData ( ( pos << 1 ) + 1 , color )
}
// SetDisplay cuts and sends a byte array to the display (without dots)
func ( t * TM1638Driver ) SetDisplay ( data [ ] byte ) {
minLength := int ( math . Min ( 8 , float64 ( len ( data ) ) ) )
for i := 0 ; i < minLength ; i ++ {
t . SendChar ( byte ( i ) , data [ i ] , false )
}
}
// SetDisplayText cuts and sends a string to the display (without dots)
func ( t * TM1638Driver ) SetDisplayText ( text string ) {
data := t . fromStringToByteArray ( text )
minLength := int ( math . Min ( 8 , float64 ( len ( data ) ) ) )
for i := 0 ; i < minLength ; i ++ {
t . SendChar ( byte ( i ) , data [ i ] , false )
}
}
// SendChar sends one byte to the specific position in the display
func ( t * TM1638Driver ) SendChar ( pos byte , data byte , dot bool ) {
if pos > 7 {
return
}
var dotData byte
if dot {
dotData = TM1638DispCtrl
}
t . sendData ( pos << 1 , data | ( dotData ) )
}
// fromStringToByteArray translates a string to a byte array with the corresponding representation for the 7-segment LCD, return and empty character if the font is not available
func ( t * TM1638Driver ) fromStringToByteArray ( str string ) [ ] byte {
chars := strings . Split ( str , "" )
data := make ( [ ] byte , len ( chars ) )
for index , char := range chars {
if val , ok := t . fonts [ char ] ; ok {
data [ index ] = val
}
}
return data
}
// AddFonts adds new custom fonts or modify the representation of existing ones
func ( t * TM1638Driver ) AddFonts ( fonts map [ string ] byte ) {
for k , v := range fonts {
t . fonts [ k ] = v
}
}
// ClearFonts removes all the fonts from the driver
func ( t * TM1638Driver ) ClearFonts ( ) {
t . fonts = make ( map [ string ] byte )
}
// NewTM1638Fonts returns a map with fonts and their corresponding byte for proper representation on the 7-segment LCD
func NewTM1638Fonts ( ) map [ string ] byte {
return map [ string ] byte {
" " : 0x00 ,
"!" : 0x86 ,
"'" : 0x22 ,
"#" : 0x7E ,
"$" : 0x6D ,
"%" : 0x00 ,
"&" : 0x00 ,
"\"" : 0x02 ,
"(" : 0x30 ,
")" : 0x06 ,
"*" : 0x63 ,
"+" : 0x00 ,
"," : 0x04 ,
"-" : 0x40 ,
"." : 0x80 ,
"/" : 0x52 ,
"0" : 0x3F ,
"1" : 0x06 ,
"2" : 0x5B ,
"3" : 0x4F ,
"4" : 0x66 ,
"5" : 0x6D ,
"6" : 0x7D ,
"7" : 0x27 ,
"8" : 0x7F ,
"9" : 0x6F ,
":" : 0x00 ,
";" : 0x00 ,
"<" : 0x00 ,
"=" : 0x48 ,
">" : 0x00 ,
"?" : 0x53 ,
"@" : 0x5F ,
"A" : 0x77 ,
"B" : 0x7F ,
"C" : 0x39 ,
"D" : 0x3F ,
"E" : 0x79 ,
"F" : 0x71 ,
"G" : 0x3D ,
"H" : 0x76 ,
"I" : 0x06 ,
"J" : 0x1F ,
"K" : 0x69 ,
"L" : 0x38 ,
"M" : 0x15 ,
"N" : 0x37 ,
"O" : 0x3F ,
"P" : 0x73 ,
"Q" : 0x67 ,
"R" : 0x31 ,
"S" : 0x6D ,
"T" : 0x78 ,
"U" : 0x3E ,
"V" : 0x2A ,
"W" : 0x1D ,
"X" : 0x76 ,
"Y" : 0x6E ,
"Z" : 0x5B ,
"[" : 0x39 ,
"\\" : 0x64 , // (this can't be the last char on a line, even in comment or it'll concat)
"]" : 0x0F ,
"^" : 0x00 ,
"_" : 0x08 ,
"`" : 0x20 ,
"a" : 0x5F ,
"b" : 0x7C ,
"c" : 0x58 ,
"d" : 0x5E ,
"e" : 0x7B ,
"f" : 0x31 ,
"g" : 0x6F ,
"h" : 0x74 ,
"i" : 0x04 ,
"j" : 0x0E ,
"k" : 0x75 ,
"l" : 0x30 ,
"m" : 0x55 ,
"n" : 0x54 ,
"o" : 0x5C ,
"p" : 0x73 ,
"q" : 0x67 ,
"r" : 0x50 ,
"s" : 0x6D ,
"t" : 0x78 ,
"u" : 0x1C ,
"v" : 0x2A ,
"w" : 0x1D ,
"x" : 0x76 ,
"y" : 0x6E ,
"z" : 0x47 ,
"{" : 0x46 ,
"|" : 0x06 ,
"}" : 0x70 ,
"~" : 0x01 ,
}
}