diff --git a/matrixclock/Display.py b/matrixclock/Display.py index c525787..ae72338 100644 --- a/matrixclock/Display.py +++ b/matrixclock/Display.py @@ -1,191 +1,189 @@ -import machine,neopixel -from time import sleep #GOES -import font - -words={"it":[0,1], - "is":[3,4], - "beer":[19,35,51], - "m1":[13,14,15], - "m2":[16,17,18], - "m3":[48,49,50,51,52], - "m4":[44,45,46,47], - "m5":[32,33,34,35], - "m6":[73,74,75], - "m7":[96,97,98,99,100], - "m8":[88,89,90,91,92], - "m9":[54,55,56,57], - "m10":[20,21,22], - "m11":[37,38,39,40,41,42], - "m12":[80,81,82,83,84,85], - "m13":[24,25,26,27,28,29,30,31], - "m14":[64,65,66,67,68,69,70,71], - "quarter":[105,106,107,108,109,110,111], - "m16":[73,74,75,76,77,78,79], - "m17":[96,97,98,99,100,101,102,103,104], - "m18":[88,89,90,91,92,93,94,95], - "m19":[54,55,56,57,58,59,60,61], - "m20":[6,7,8,9,10,11], - "half":[112,113,114,115], - "past":[117,118,119,120], - "to":[120,121], - "h1":[150,151,152], - "h2":[153,154,155], - "h3":[132,133,134,135,136], - "h4":[140,141,142,143], - "h5":[156,157,158,159], - "h6":[137,138,139], - "h7":[123,124,125,126,127], - "h8":[128,129,130,131,132], - "h9":[169,170,171,172], - "h10":[167,168,169], - "h11":[176,177,178,179,180,181], - "h12":[144,145,146,147,148,149], - "midnight":[160,161,162,163,164,165,166,167], - "in":[192,193], - "the":[195,196,197], - "morning":[208,209,210,211,212,213,214], - "afternoon":[199,200,201,202,203,204,205,206,207], - "evening":[224,225,226,227,228,229,230], - "at":[216,217], - "night":[219,220,221,222,223], - "dot":[182,183,184], - "gin":[173,174,175], - "oclock":[185,187,188,189,190,191], - "and":[232,233,234], - "cold":[236,237,238,239], - "cool":[240,241,242,243], - "warm":[245,256,257,258], - "hot":[252,253,254], - "beer":[19,35,51,67], - } - -class Display(object): - """Initialises a NeoPixel-String.""" - def __init__(self,DataPin,Rows=16,Columns=16): - self.np=neopixel.NeoPixel(machine.Pin(DataPin),Rows*Columns) - self.number=Rows*Columns - self.Rows=Rows - self.Columns=Columns - - def Write(self,Pos,Colour=(0,0,0), Immediate=True): - """write(Pos,Colour=(0,0,0), Immediate=True): Writes a colour (given as an RGB triplet) to the Pixel - at position 'Pos'. If 'Immediate' is set, change immediately, otherwise, wait until the display is - explicitly written or a write with 'Immediate' is called.""" - if Pos >= self.number: - print("Out of range") - else: - self.np[self.Weave(Pos)]=Colour - if Immediate: - self.np.write() - - def Clear(self,color=(0,0,0),Immediate=True): - """Clears all pixels""" - for i in range(self.number): - self.np[i]=color - if Immediate: - self.np.write() - - def WriteWord(self,word,colour=(50,50,50),Immediate=False): - try: - for i in words[word]: - self.Write(i,colour,False) - if Immediate == True: - self.np.write() - except KeyError: - #print("No such word") - pass - - def WriteSentence(self,sentence,color=(25,25,0)): - self.Clear(Immediate=False) - for word in sentence.split(" "): - self.WriteWord(word,color,Immediate=False) - self.np.write() - - def Scroll(self,Direction,Fill=[(0,0,0)]*16): - newbuf=bytearray(b'') - if Direction == 'l': - for Row in range(0,self.Rows,2): - newbuf += self.np.buf[Row*16*3+3:Row*16*3+48] - newbuf+=bytearray([Fill[Row][1],Fill[Row][0],Fill[Row][2]]) - newbuf += bytearray([Fill[Row+1][1],Fill[Row+1][0],Fill[Row+1][2]]) - newbuf += self.np.buf[Row*16*3+48:Row*16*3+93] - self.np.buf=newbuf - self.np.write() - if Direction == 'r': - for Row in range(0,self.Rows): - for Col in range(self.Columns-1,0,-1): - self.WriteXY(Col,Row,self.GetXY(Col-1,Row),Immediate=False) - self.WriteXY(0,Row,Fill[Row],Immediate=False) - if Direction == 'd': - for Row in range(self.Rows-1,0,-1): - for Col in range(self.Columns): - self.WriteXY(Col,Row,self.GetXY(Col,Row-1),Immediate=False) - for Col in range(self.Columns): - self.WriteXY(Col,0,Fill[Col],Immediate=False) - if Direction == 'u': - for Row in range(0,self.Rows-1): - for Col in range(self.Columns): - self.WriteXY(Col,Row,self.GetXY(Col,Row+1),Immediate=False) - for Col in range(self.Columns): - self.WriteXY(Col,self.Rows-1,Fill[Col],Immediate=False) - self.np.write() - -# def Scroll(self,Direction,Fill=[(0,0,0)]*16): -# if Direction == 'l': -# for Row in range(0,self.Rows): -# for Col in range(0,self.Columns-1): -# self.WriteXY(Col,Row,self.GetXY(Col+1,Row),Immediate=False) -# #for Row in range(0,self.Rows): -# self.WriteXY(self.Columns-1,Row,Fill[Row],Immediate=False) -# if Direction == 'r': -# for Row in range(0,self.Rows): -# for Col in range(self.Columns-1,0,-1): -# self.WriteXY(Col,Row,self.GetXY(Col-1,Row),Immediate=False) -# self.WriteXY(0,Row,Fill[Row],Immediate=False) -# if Direction == 'd': -# for Row in range(self.Rows-1,0,-1): -# for Col in range(self.Columns): -# self.WriteXY(Col,Row,self.GetXY(Col,Row-1),Immediate=False) -# for Col in range(self.Columns): -# self.WriteXY(Col,0,Fill[Col],Immediate=False) -# if Direction == 'u': -# for Row in range(0,self.Rows-1): -# for Col in range(self.Columns): -# self.WriteXY(Col,Row,self.GetXY(Col,Row+1),Immediate=False) -# for Col in range(self.Columns): -# self.WriteXY(Col,self.Rows-1,Fill[Col],Immediate=False) -# self.np.write() - - def ScrollLetter(self,Direction,Text,Speed,Color=[(50,50,50)],BGColor=[(0,0,0)]): - for index,Letter in enumerate(Text): - for X in range(3,14): # FIXME: Adjust for x/y and direction - self.Scroll(Direction,font.CharacterColumn(Letter,X,Color[index%len(Color)],BGColor[index%len(BGColor)])) - sleep(Speed) - - def Num2Column(self,Number): - return(Number-int(Number/self.Columns)*self.Columns) - - def Num2Row(self,Number): - return(int(Number/self.Columns)) - - def Weave(self,Pos): - Row=self.Num2Row(Pos) - if Row%2 == 1: - NewPos=(Row+1)*self.Columns-self.Num2Column(Pos)-1 - else: - NewPos=Pos - return NewPos - - def WriteXY(self,X,Y,Color=(24,0,0),Immediate=True): - Pos=self.Write(Y*self.Columns+X,Color,Immediate) - - def GetXY(self,X,Y): - return self.np[self.XY2Num(X,Y)] - - def XY2Num(self,X,Y): - return self.Weave(Y*self.Columns+X) - - def TestPattern(self): - for i in range(256): - self.np[i]=(0,0,i) - self.np.write() \ No newline at end of file +import machine,neopixel +from time import sleep +import font + +words={"it":[0,1], + "is":[3,4], + "beer":[19,35,51], + "m1":[13,14,15], + "m2":[16,17,18], + "m3":[48,49,50,51,52], + "m4":[44,45,46,47], + "m5":[32,33,34,35], + "m6":[73,74,75], + "m7":[96,97,98,99,100], + "m8":[88,89,90,91,92], + "m9":[54,55,56,57], + "m10":[20,21,22], + "m11":[37,38,39,40,41,42], + "m12":[80,81,82,83,84,85], + "m13":[24,25,26,27,28,29,30,31], + "m14":[64,65,66,67,68,69,70,71], + "quarter":[105,106,107,108,109,110,111], + "m16":[73,74,75,76,77,78,79], + "m17":[96,97,98,99,100,101,102,103,104], + "m18":[88,89,90,91,92,93,94,95], + "m19":[54,55,56,57,58,59,60,61], + "m20":[6,7,8,9,10,11], + "half":[112,113,114,115], + "past":[117,118,119,120], + "to":[120,121], + "h1":[150,151,152], + "h2":[153,154,155], + "h3":[132,133,134,135,136], + "h4":[140,141,142,143], + "h5":[156,157,158,159], + "h6":[137,138,139], + "h7":[123,124,125,126,127], + "h8":[128,129,130,131,132], + "h9":[169,170,171,172], + "h10":[167,168,169], + "h11":[176,177,178,179,180,181], + "h12":[144,145,146,147,148,149], + "midnight":[160,161,162,163,164,165,166,167], + "in":[192,193], + "the":[195,196,197], + "morning":[208,209,210,211,212,213,214], + "afternoon":[199,200,201,202,203,204,205,206,207], + "evening":[224,225,226,227,228,229,230], + "at":[216,217], + "night":[219,220,221,222,223], + "dot":[182,183,184], + "gin":[173,174,175], + "oclock":[185,187,188,189,190,191], + "and":[232,233,234], + "cold":[236,237,238,239], + "cool":[240,241,242,243], + "warm":[245,256,257,258], + "hot":[252,253,254], + "beer":[19,35,51,67], + } + +class Display(object): + """Initialises a NeoPixel-String.""" + def __init__(self,DataPin,Rows=16,Columns=16): + self.np=neopixel.NeoPixel(machine.Pin(DataPin),Rows*Columns) + self.number=Rows*Columns + self.Rows=Rows + self.Columns=Columns + + def Write(self,Pos,Colour=(0,0,0), Immediate=True): + """write(Pos,Colour=(0,0,0), Immediate=True): Writes a colour (given as an RGB triplet) to the Pixel + at position 'Pos'. If 'Immediate' is set, change immediately, otherwise, wait until the display is + explicitly written or a write with 'Immediate' is called.""" + if Pos >= self.number: + print("Out of range") + else: + self.np[self.Weave(Pos)]=Colour + if Immediate: + self.np.write() + + def Clear(self,color=(0,0,0),Immediate=True): + """Clears all pixels""" + for i in range(self.number): + self.np[i]=color + if Immediate: + self.np.write() + + def WriteWord(self,word,colour=(50,50,50),Immediate=False): + try: + for i in words[word]: + self.Write(i,colour,False) + if Immediate == True: + self.np.write() + except KeyError: + #print("No such word") + pass + + def WriteSentence(self,sentence,color=(25,25,0)): + self.Clear(Immediate=False) + for word in sentence.split(" "): + self.WriteWord(word,color,Immediate=False) + self.np.write() + + def Scroll(self,Direction,Fill=[(0,0,0)]*16): + """Optimized scroll using direct buffer manipulation for all directions.""" + newbuf=bytearray(b'') + + if Direction == 'l': + # Optimized left scroll - existing implementation + for Row in range(0,self.Rows,2): + newbuf += self.np.buf[Row*16*3+3:Row*16*3+48] + newbuf+=bytearray([Fill[Row][1],Fill[Row][0],Fill[Row][2]]) + newbuf += bytearray([Fill[Row+1][1],Fill[Row+1][0],Fill[Row+1][2]]) + newbuf += self.np.buf[Row*16*3+48:Row*16*3+93] + self.np.buf=newbuf + + elif Direction == 'r': + # Optimized right scroll using buffer manipulation + for Row in range(0,self.Rows,2): + # Add fill pixels at the start + newbuf += bytearray([Fill[Row][1],Fill[Row][0],Fill[Row][2]]) + newbuf += bytearray([Fill[Row+1][1],Fill[Row+1][0],Fill[Row+1][2]]) + # Copy existing pixels (minus the last one from each row) + newbuf += self.np.buf[Row*16*3:Row*16*3+45] + newbuf += self.np.buf[Row*16*3+48:Row*16*3+93] + self.np.buf=newbuf + + elif Direction == 'u': + # Optimized up scroll - skip first row, add fill at bottom + newbuf = self.np.buf[self.Columns*3:] # Skip first row + for Col in range(self.Columns): + color = Fill[Col] + newbuf += bytearray([color[1], color[0], color[2]]) + self.np.buf = newbuf + + elif Direction == 'd': + # Optimized down scroll - add fill at top, skip last row + for Col in range(self.Columns): + color = Fill[Col] + newbuf += bytearray([color[1], color[0], color[2]]) + newbuf += self.np.buf[:-self.Columns*3] # Skip last row + self.np.buf = newbuf + + self.np.write() + + def ScrollLetter(self,Direction,Text,Speed,Color=[(50,50,50)],BGColor=[(0,0,0)]): + """Optimized letter scrolling with pre-calculated columns.""" + # Pre-calculate all columns for all letters + all_columns = [] + for index,Letter in enumerate(Text): + for X in range(3,14): + all_columns.append( + font.CharacterColumn(Letter, X, + Color[index % len(Color)], + BGColor[index % len(BGColor)]) + ) + + # Now scroll with pre-calculated data + for column in all_columns: + self.Scroll(Direction, column) + sleep(Speed) + + def Num2Column(self,Number): + return(Number-int(Number/self.Columns)*self.Columns) + + def Num2Row(self,Number): + return(int(Number/self.Columns)) + + def Weave(self,Pos): + Row=self.Num2Row(Pos) + if Row%2 == 1: + NewPos=(Row+1)*self.Columns-self.Num2Column(Pos)-1 + else: + NewPos=Pos + return NewPos + + def WriteXY(self,X,Y,Color=(24,0,0),Immediate=True): + Pos=self.Write(Y*self.Columns+X,Color,Immediate) + + def GetXY(self,X,Y): + return self.np[self.XY2Num(X,Y)] + + def XY2Num(self,X,Y): + return self.Weave(Y*self.Columns+X) + + def TestPattern(self): + for i in range(256): + self.np[i]=(0,0,i) + self.np.write()