From bb15dc0e61cdc9f827ebe3fadc4e89e590ec0227 Mon Sep 17 00:00:00 2001 From: Aus000Alex <143391931+Aus000Alex@users.noreply.github.com> Date: Wed, 14 Feb 2024 10:14:48 +0100 Subject: [PATCH] initial commit Added files form localy working version --- baby.pbm | Bin 0 -> 87 bytes baby_bounce01.pbm | Bin 0 -> 343 bytes baby_bounce02.pbm | Bin 0 -> 343 bytes baby_bounce03.pbm | Bin 0 -> 343 bytes baby_bounce04.pbm | Bin 0 -> 343 bytes baby_zzz01.pbm | Bin 0 -> 343 bytes baby_zzz02.pbm | Bin 0 -> 343 bytes baby_zzz03.pbm | Bin 0 -> 343 bytes baby_zzz04.pbm | Bin 0 -> 343 bytes book.pbm | Bin 0 -> 87 bytes bubble.pbm | Bin 0 -> 87 bytes bubble.xcf | Bin 0 -> 725 bytes button_test.py | 10 + call.pbm | Bin 0 -> 87 bytes call_animate01.pbm | Bin 0 -> 87 bytes call_animate03.pbm | Bin 0 -> 87 bytes disc.pbm | Bin 0 -> 87 bytes display.py | 39 ++ eat01.pbm | Bin 0 -> 343 bytes eat02.pbm | Bin 0 -> 343 bytes eat03.pbm | Bin 0 -> 343 bytes eat04.pbm | Bin 0 -> 343 bytes eat05.pbm | Bin 0 -> 343 bytes eat06.pbm | Bin 0 -> 343 bytes eat07.pbm | Bin 0 -> 343 bytes eat08.pbm | Bin 0 -> 343 bytes firstaid.pbm | Bin 0 -> 87 bytes food.pbm | Bin 0 -> 87 bytes game.pbm | Bin 0 -> 87 bytes heart.pbm | Bin 0 -> 87 bytes heart_plus.pbm | Bin 0 -> 319 bytes icon.py | 665 ++++++++++++++++++++++++++++++++++ lib/sdcard.py | 309 ++++++++++++++++ lightbulb.pbm | Bin 0 -> 87 bytes main.py | 270 ++++++++++++++ poop01.pbm | Bin 0 -> 87 bytes poop02.pbm | Bin 0 -> 87 bytes poop03.pbm | Bin 0 -> 87 bytes poop04.pbm | Bin 0 -> 87 bytes potty01.pbm | Bin 0 -> 343 bytes potty02.pbm | Bin 0 -> 343 bytes potty03.pbm | Bin 0 -> 343 bytes potty04.pbm | Bin 0 -> 343 bytes potty05.pbm | Bin 0 -> 343 bytes potty06.pbm | Bin 0 -> 343 bytes potty07.pbm | Bin 0 -> 343 bytes potty08.pbm | Bin 0 -> 343 bytes potty09.pbm | Bin 0 -> 343 bytes potty10.pbm | Bin 0 -> 343 bytes potty11.pbm | Bin 0 -> 343 bytes potty12.pbm | Bin 0 -> 343 bytes potty13.pbm | Bin 0 -> 343 bytes potty14.pbm | Bin 0 -> 343 bytes raw_assets/baby_zzz01.xcf | Bin 0 -> 1069 bytes raw_assets/baby_zzz02.xcf | Bin 0 -> 1069 bytes raw_assets/baby_zzz03.xcf | Bin 0 -> 1093 bytes raw_assets/baby_zzz04.xcf | Bin 0 -> 1089 bytes raw_assets/baby_zzz05.xcf | Bin 0 -> 1101 bytes raw_assets/bubble.xcf | Bin 0 -> 725 bytes raw_assets/call_animate01.xcf | Bin 0 -> 782 bytes raw_assets/call_animate02.xcf | Bin 0 -> 754 bytes raw_assets/call_animate03.xcf | Bin 0 -> 779 bytes raw_assets/potty01.xcf | Bin 0 -> 1559 bytes raw_assets/potty02.xcf | Bin 0 -> 1214 bytes raw_assets/potty03.xcf | Bin 0 -> 796 bytes raw_assets/potty04.xcf | Bin 0 -> 796 bytes raw_assets/potty05.xcf | Bin 0 -> 796 bytes raw_assets/potty06.xcf | Bin 0 -> 796 bytes raw_assets/potty07.xcf | Bin 0 -> 794 bytes raw_assets/potty08.xcf | Bin 0 -> 816 bytes raw_assets/potty09.xcf | Bin 0 -> 808 bytes raw_assets/potty10.xcf | Bin 0 -> 1255 bytes raw_assets/potty11.xcf | Bin 0 -> 1209 bytes raw_assets/potty12.xcf | Bin 0 -> 1230 bytes raw_assets/skull01.xcf | Bin 0 -> 718 bytes raw_assets/skull02.xcf | Bin 0 -> 694 bytes sdcardtest.py | 104 ++++++ skull01.pbm | 4 + skull02.pbm | 4 + ssd1306.py | 155 ++++++++ toilet.pbm | Bin 0 -> 87 bytes 81 files changed, 1560 insertions(+) create mode 100644 baby.pbm create mode 100644 baby_bounce01.pbm create mode 100644 baby_bounce02.pbm create mode 100644 baby_bounce03.pbm create mode 100644 baby_bounce04.pbm create mode 100644 baby_zzz01.pbm create mode 100644 baby_zzz02.pbm create mode 100644 baby_zzz03.pbm create mode 100644 baby_zzz04.pbm create mode 100644 book.pbm create mode 100644 bubble.pbm create mode 100644 bubble.xcf create mode 100644 button_test.py create mode 100644 call.pbm create mode 100644 call_animate01.pbm create mode 100644 call_animate03.pbm create mode 100644 disc.pbm create mode 100644 display.py create mode 100644 eat01.pbm create mode 100644 eat02.pbm create mode 100644 eat03.pbm create mode 100644 eat04.pbm create mode 100644 eat05.pbm create mode 100644 eat06.pbm create mode 100644 eat07.pbm create mode 100644 eat08.pbm create mode 100644 firstaid.pbm create mode 100644 food.pbm create mode 100644 game.pbm create mode 100644 heart.pbm create mode 100644 heart_plus.pbm create mode 100644 icon.py create mode 100644 lib/sdcard.py create mode 100644 lightbulb.pbm create mode 100644 main.py create mode 100644 poop01.pbm create mode 100644 poop02.pbm create mode 100644 poop03.pbm create mode 100644 poop04.pbm create mode 100644 potty01.pbm create mode 100644 potty02.pbm create mode 100644 potty03.pbm create mode 100644 potty04.pbm create mode 100644 potty05.pbm create mode 100644 potty06.pbm create mode 100644 potty07.pbm create mode 100644 potty08.pbm create mode 100644 potty09.pbm create mode 100644 potty10.pbm create mode 100644 potty11.pbm create mode 100644 potty12.pbm create mode 100644 potty13.pbm create mode 100644 potty14.pbm create mode 100644 raw_assets/baby_zzz01.xcf create mode 100644 raw_assets/baby_zzz02.xcf create mode 100644 raw_assets/baby_zzz03.xcf create mode 100644 raw_assets/baby_zzz04.xcf create mode 100644 raw_assets/baby_zzz05.xcf create mode 100644 raw_assets/bubble.xcf create mode 100644 raw_assets/call_animate01.xcf create mode 100644 raw_assets/call_animate02.xcf create mode 100644 raw_assets/call_animate03.xcf create mode 100644 raw_assets/potty01.xcf create mode 100644 raw_assets/potty02.xcf create mode 100644 raw_assets/potty03.xcf create mode 100644 raw_assets/potty04.xcf create mode 100644 raw_assets/potty05.xcf create mode 100644 raw_assets/potty06.xcf create mode 100644 raw_assets/potty07.xcf create mode 100644 raw_assets/potty08.xcf create mode 100644 raw_assets/potty09.xcf create mode 100644 raw_assets/potty10.xcf create mode 100644 raw_assets/potty11.xcf create mode 100644 raw_assets/potty12.xcf create mode 100644 raw_assets/skull01.xcf create mode 100644 raw_assets/skull02.xcf create mode 100644 sdcardtest.py create mode 100644 skull01.pbm create mode 100644 skull02.pbm create mode 100644 ssd1306.py create mode 100644 toilet.pbm diff --git a/baby.pbm b/baby.pbm new file mode 100644 index 0000000000000000000000000000000000000000..6f5c07986529569d7ba268bd7e3a5de3bdb43522 GIT binary patch literal 87 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFa2Kj5IyAh6-Wh6@b>4FYXI*dXAbV1IxC3;^#7kcR|8?89L3 ZgAd{23=f!rY=-~;8-Qf}e;`3I003E$C!YWS literal 0 HcmV?d00001 diff --git a/baby_bounce03.pbm b/baby_bounce03.pbm new file mode 100644 index 0000000000000000000000000000000000000000..7ceda96d03b5491504cfbc1c4555ed9bd2ca47af GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SF|l}^K|V8X0CJ8Qg2)4m2=b61h3DKqB&gKqRFA0Q6NLh5!Hn literal 0 HcmV?d00001 diff --git a/baby_zzz01.pbm b/baby_zzz01.pbm new file mode 100644 index 0000000000000000000000000000000000000000..17ec879138dbf966ed9b42a08f0b9d99a702d71d GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFGpV(tr;^7O;WX u57--k04Dw=_y7O^ literal 0 HcmV?d00001 diff --git a/book.pbm b/book.pbm new file mode 100644 index 0000000000000000000000000000000000000000..566955d7c4524e34dac5ebfa17149f25a3ccc186 GIT binary patch literal 87 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SF^0WP@?xGytrf4{`ti literal 0 HcmV?d00001 diff --git a/bubble.xcf b/bubble.xcf new file mode 100644 index 0000000000000000000000000000000000000000..13fa5e94506e0b536ca2389ad89d066749437918 GIT binary patch literal 725 zcmZva%SyvQ6o!)`UV6cLUAY)<&@KYa69`ri7lN;lrpa`$NlKDx3kBVYFW?Kf^$mP1 zw?h5@X$Gd?8U8unx#V^-QY8~H3uE!r^L+=_u2h5nfLy2!FurHk0uIs z2yH-YJ+7F2N6-({l6aUGW=RsIC1QQ={eB(=Wi%AesvL>iyZZ-L+PYOGfs8zvtD))s z>J;UC9Elx&*cv{jnis76KGENEK_1t3n qWFT#<_GSp)jDp_-t9`D#-c619Zd&-jnw4**9f8gKvr literal 0 HcmV?d00001 diff --git a/call_animate03.pbm b/call_animate03.pbm new file mode 100644 index 0000000000000000000000000000000000000000..deae954e6ba798e47dd8571eb1add811e67df08d GIT binary patch literal 87 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SF_J*W{e#LsWli>sa%Y)5nHYiCkdcYu4*-@T8!rF= literal 0 HcmV?d00001 diff --git a/disc.pbm b/disc.pbm new file mode 100644 index 0000000000000000000000000000000000000000..d9400ffc14e9234ec06c541eecbd0d9be181b0d2 GIT binary patch literal 87 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGd58O@bgtD$SF>|Zkw-WY;D4@2K#>?l2QNw@;Qs(pEB^yT z8t{NgJ`h>J1|pvsHvq|VmOzrRf#Cpu2MdCPh#dY16k&M4+yEr&{{smI K`+p#kQUCxM_$k={ literal 0 HcmV?d00001 diff --git a/eat04.pbm b/eat04.pbm new file mode 100644 index 0000000000000000000000000000000000000000..ae04fa3f94c48c149a60567290ef95842eac11b8 GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFpNCO@)$p<0}*g)hn;|3sk&Jsv6HZU9jlI=f0WCsg~oWO)2dw4+X!ykbp U!vp39AX)z(NHEy{1Cf*h0Am*`-~a#s literal 0 HcmV?d00001 diff --git a/eat05.pbm b/eat05.pbm new file mode 100644 index 0000000000000000000000000000000000000000..6a82821a3d0a7538c40432a64a0832c628e35772 GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFfn3M?QI91yKpnrDFzCnfwey zJ~M6rlIJXeBx3`^0U+7_14MSPfXE3<2(pI<#6J8HNHRQNZUB|5zyTs5A`ta1N+1zr()myWP-FoskYrrI tasWt9-~f?5CLnV1A+QJ&ScC^e9{va<86Ge<0Ll9QK!U;kABdzB004H|CRhLf literal 0 HcmV?d00001 diff --git a/eat07.pbm b/eat07.pbm new file mode 100644 index 0000000000000000000000000000000000000000..87278ba47449bd31bbdfb33a211e4ca7e33ee358 GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFBamcxz}x^N>;D4@2K#>?l2QNwC{iYe literal 0 HcmV?d00001 diff --git a/firstaid.pbm b/firstaid.pbm new file mode 100644 index 0000000000000000000000000000000000000000..424b90271f2564b2af62a2efe1b8fd155a52e808 GIT binary patch literal 87 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFao{~*92{=)u`1CwJD2>O5W{{&$YCl@PTMwUD>qvtY4ckznBfK|ToxWMBXQ*xwP% literal 0 HcmV?d00001 diff --git a/game.pbm b/game.pbm new file mode 100644 index 0000000000000000000000000000000000000000..9c7b680309669b456ac3a5281e29fa1d3f40bf30 GIT binary patch literal 87 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFA7_|N<=|HJ==9}Ec~DFy%)>K9i4 literal 0 HcmV?d00001 diff --git a/heart.pbm b/heart.pbm new file mode 100644 index 0000000000000000000000000000000000000000..2f321402a0b1240d1854a2e0fc90b078806d5a95 GIT binary patch literal 87 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFZ7kYQl5D02B3|MULe|9?QR{zv@}`w#LD_zy5M005?aAZ!2t literal 0 HcmV?d00001 diff --git a/heart_plus.pbm b/heart_plus.pbm new file mode 100644 index 0000000000000000000000000000000000000000..76ddad1297c80ca280afcd0304305b94c509cbe3 GIT binary patch literal 319 zcmY+9Jqp4=5QQhC2&CB~?0~gFLkhbsEW{#`D<}pDh)VnctIg5&C>|l@7Qt~QQG$=< zV|e>!d0S-h1ebNWy_I|1J#n?p3w)IIwK|_LP3E&CO|jVIcsbq=)9Msw3(T?@2I(f~ z0H{?2A$d(MqR!Au(c4n1iRF!uO`#R?)kqmfePc$Paket^RulY@O?H@aw9qRdmk|z4 sLV3ysLJqUIZBI+Y%}q~D)B;35IslF~{6mQYSPlYcFH{@^2%S*$0sL^ZRsaA1 literal 0 HcmV?d00001 diff --git a/icon.py b/icon.py new file mode 100644 index 0000000..564bd2f --- /dev/null +++ b/icon.py @@ -0,0 +1,665 @@ +import framebuf +from machine import Pin +from time import sleep +from os import listdir +import gc + +class Icon(): + """ Models an icon and all the properties it requires """ + __image = None + __x = 0 + __y = 0 + __invert = False + __width = 16 + __height = 16 + __name = "Empty" + + + def __init__(self, filename:None, width=None, height=None, x=None, y=None, name=None): + """ Sets up the default values """ + if width: + self.__width = width + if height: + self.__height = height + if name: + self.__name = name + if x: + self.__x = x + if y: + self.__y = y + if filename is not None: + self.__image = self.loadicons(filename) + + @property + def image(self): + """ gets the icon image """ + + return self.__image + + @image.setter + def image(self, buf): + """ Sets the icon image """ + + self.__image = buf + + @property + def x(self)->int: + """ Gets the X value """ + + return self.__x + + + @x.setter + def x(self, value): + """ Sets the X value """ + + self.__x = value + + + @property + def width(self)->int: + """ Get the width""" + + return self.__width + + + @width.setter + def width(self, value): + """ Sets the icon width """ + + self.__width = value + + + @property + def height(self): + """ Returns height """ + return self.__height + + + @height.setter + def height(self, value): + """ Gets the height """ + + self.__height = value + + + @property + def name(self): + """ Gets the name """ + + return self.__name + + + @name.setter + def name(self, value): + """ Sets the icon name """ + + self.__name = value + + + @property + def y(self)->int: + """ Gets the y value """ + + return self.__y + + + @y.setter + def y(self, value): + """ Sets the Y value """ + + self.__y = value + + + @property + def invert(self)->bool: + """ Flips the bits in the image so white become black etc and returns the image """ + print("Invert is", self.__invert) + return self.__invert + + @invert.setter + def invert(self, value:bool): + """ Inverts the icon colour """ + + image = self.__image + for x in range(0,self.width): + for y in range(0, self.height): + pxl = image.pixel(x,y) + if pxl == 0: + image.pixel(x,y,1) + else: + image.pixel(x,y,0) + + self.__image = image + self.__invert = value + # print("Invert is", self.__invert) + + def loadicons(self, file): + # print(file) + with open(file, 'rb') as f: + f.readline() # magic number + f.readline() # creator comment + f.readline() # dimensions + data = bytearray(f.read()) + fbuf = framebuf.FrameBuffer(data, self.__width,self.__height, framebuf.MONO_HLSB) + # print(self.__name, self.__width, self.__height) + return fbuf + +class Toolbar(): + """ Models the toolbar """ + __icon_array = [] + __framebuf = framebuf.FrameBuffer(bytearray(160*64*1), 160, 16, framebuf.MONO_HLSB) + __spacer = 1 + __selected_item = None + __selected_index = -1 # -1 means no item selected + + def __init__(self): + # print("building toolbar") + self.__framebuf = framebuf.FrameBuffer(bytearray(160*64*8), 160, 16, framebuf.MONO_HLSB) + + def additem(self, icon): + self.__icon_array.append(icon) + print("mehr icons...") + + + def remove(self, icon): + self.__icon_array.remove(icon) + + def getlength(self): + return len(self.__icon_array) + + """ + @property + def data(self): + + x = 0 + count = 0 + for icon in self.__icon_array: + # print("x:",x) + count += 1 + if type(icon) == Icon: + self.__framebuf.blit(icon.image, x, 0) + if type(icon) == Animate: + self.__framebuf.blit(icon.__frames[icon.__current_frame].image, x, 0) + fb = self.__framebuf + x += icon.width + self.spacer + return fb + """ + + @property + def spacer(self): + """ returns the spacer value""" + return self.__spacer + + @spacer.setter + def spacer(self, value): + """ Sets the spacer value""" + self.__spacer = value + + def show(self, oled): + oled.blit(self.__framebuf, 0,0) + # oled.show() + + def select(self, index, oled): + """ Set the item in the index to inverted """ + # for item in self.__icon_array: + # item.invert = False + self.__icon_array[index].invert = True + self.__selected_index = index + offsetvalue = 3 + x=0 + for loopcount in range(len(self.__icon_array)): + offset = loopcount - offsetvalue + zeiger = (index + offset) % len(self.__icon_array) + # print("x:",x) + if type(self.__icon_array[zeiger]) == Icon: + self.__framebuf.blit(self.__icon_array[zeiger].image, x, 0) + if type(self.__icon_array[zeiger]) == Animate: + self.__framebuf.blit(self.__icon_array[zeiger].__frames[self.__icon_array[zeiger].__current_frame].image, x, 0) + fb = self.__framebuf + x += self.__icon_array[zeiger].width + self.spacer + return fb + + def unselect(self, index, oled): + self.__icon_array[index].invert = False + self.__selected_index = -1 + self.show(oled) + + @property + def selected_item(self): + """ Returns the name of the currently selected icon """ + self.__selected_item = self.__icon_array[self.__selected_index].name + return self.__selected_item + +class Animate(): + __frames = [] + __current_frame = 0 + __speed = "normal" # Other speeds are 'fast' and 'slow' - it just adds frames or skips frames + __speed_value = 0 + __done = False # Has the animation completed + __loop_count = 0 + __bouncing = False + __animation_type = "default" + __pause = 0 + __set = False + __x = 0 + __y = 0 + __width = 16 + __height = 16 + __cached = False + __filename = None + """ other animations types: + - loop + - bounce + - reverse + """ + @property + def set(self)->bool: + return self.__set + + @set.setter + def set(self, value:bool): + self.__set = value + if value == True: + self.load() + else: + self.unload() + + + @property + def speed(self): + """ Returns the current speed """ + return self.__speed + + @speed.setter + def speed(self, value:str): + if value in ['very slow','slow','normal','fast']: + self.__speed = value + if value == 'very slow': + self.__pause = 10 + self.__speed_value = 10 + if value == 'slow': + self.__pause = 1 + self.__speed_value = 1 + if value == "normal": + self.__pause = 0 + self.__speed_value = 0 + else: + print(value, "is not a valid value, try 'fast','normal' or 'slow'") + + @property + def animation_type(self): + return self.__animation_type + + @animation_type.setter + def animation_type(self, value): + if value in ['default','loop','bounce','reverse']: + self.__animation_type = value + else: + print(value," is not a valid Animation type - it should be 'loop','bounce','reverse' or 'default'") + + def __init__(self, frames=None, animation_type:str=None,x:int=None,y:int=None, width:int=None, height:int=None, filename=None): + """ setup the animation """ + + if x: + self.__x = x + if y: + self.__y = y + if width: + self.__width = width + if height: + self.__height = height + self.__current_frame = 0 + if frames is not None: + self.__frames = frames + self.__done = False + self.__loop_count = 1 + if animation_type is not None: + self.animation_type = animation_type + if filename: + self.__filename = filename + + @property + def filename(self): + """ Returns the current filename""" + return self.__filename + + @filename.setter + def filename(self, value): + """ Sets the filename """ + self.__filename = value + + def forward(self): + """ progress the current frame """ + if self.__speed == 'normal': + self.__current_frame +=1 + + if self.__speed in ['very slow','slow']: + if self.__pause > 0: + self.__pause -= 1 + else: + self.__current_frame +=1 + self.__pause = self.__speed_value + + if self.__speed == 'fast': + if self.__current_frame < self.frame_count +2: + self.__current_frame +=2 + else: + self.__current_frame +=1 + + def reverse(self): + if self.__speed == 'normal': + self.__current_frame -=1 + + if self.__speed in ['very slow','slow']: + if self.__pause > 0: + self.__pause -= 1 + else: + self.__current_frame -=1 + self.__pause = self.__speed_value + + if self.__speed == 'fast': + if self.__current_frame < self.frame_count +2: + self.__current_frame -=2 + else: + self.__current_frame -=1 + + def load(self): + """ load the animation files """ + + # load the files from disk + if not self.__cached: + files = listdir() + array = [] + for file in files: + if (file.startswith(self.__filename)) and (file.endswith('.pbm')): + array.append(Icon(filename=file, width=self.__width, height=self.__height, x=self.__x, y=self.__y, name=file)) + self.__frames = array + self.__cached = True + + def unload(self): + """ free up memory """ + + self.__frames = None + self.__cached = False + gc.collect() + + def animate(self, oled): + """ Animates the frames based on the animation type and for the number of times specified """ + + cf = self.__current_frame # Current Frame number - used to index the frames array + frame = self.__frames[cf] + oled.blit(frame.image, frame.x, frame.y) + + if self.__animation_type == "loop": + # Loop from the first frame to the last, for the number of cycles specificed, and then set done to True + self.forward() + + if self.__current_frame > self.frame_count: + self.__current_frame = 0 + self.__loop_count -=1 + if self.__loop_count == 0: + self.__done = True + + if self.__animation_type == "bouncing": + + # Loop from the first frame to the last, and then back to the first again, then set done to True + if self.__bouncing: + + if self.__current_frame == 0: + if self.__loop_count == 0: + self.__done == True + else: + if self.__loop_count >0: + self.__loop_count -=1 + self.forward() + self.__bouncing = False + if self.__loop_count == -1: + # bounce infinately + self.forward() + self.__bouncing = False + if (self.__current_frame < self.frame_count) and (self.__current_frame>0): + self.reverse() + else: + if self.__current_frame == 0: + if self.__loop_count == 0: + self.__done == True + elif self.__loop_count == -1: + # bounce infinatey + self.forward() + else: + self.forward() + self.__loop_count -= 1 + elif self.__current_frame == self.frame_count: + self.reverse() + self.__bouncing = True + else: + self.forward() + + if self.__animation_type == "default": + # loop through from first frame to last, then set done to True + + if self.__current_frame == self.frame_count: + self.__current_frame = 0 + self.__done = True + else: + self.forward() + + @property + def frame_count(self): + """ Returns the total number of frames in the animation """ + return len(self.__frames)-1 + + @property + def done(self): + """ Has the animation completed """ + if self.__done: + self.__done = False + return True + else: + return False + + def loop(self, no:int=None): + """ Loops the animation + if no is None or -1 the animation will continue looping until animate.stop() is called """ + + if no is not None: + self.__loop_count = no + else: + self.__loop_count = -1 + self.__animation_type = "loop" + + def stop(self): + self.__loop_count = 0 + self.__bouncing = False + self.__done = True + + def bounce(self, no:int=None): + """ Loops the animation forwared, then backward, the number of time specified in no, + if there is no number provided it will animate infinately """ + + self.__animation_type = "bouncing" + if no is not None: + self.__loop_count = no + else: + self.__loop_count = -1 + + @property + def width(self): + """ Gets the icon width """ + return self.__width + + @width.setter + def width(self, value): + """ Sets the icon width """ + self.__width = value + + @property + def height(self): + """ Gets the icon height """ + return self.__width + + @height.setter + def height(self, value): + """ Sets the icon height """ + self.__height = value + + +class Button(): + """ Models a button, check the status with is_pressed """ + + # The private variables + __pressed = False + __pin = 0 + __button_down = False + + def __init__(self, pin:int): + """ Sets up the button """ + + self.__pin = Pin(pin, Pin.IN, Pin.PULL_DOWN) + self.__pressed = False + + @property + def is_pressed(self)->bool: + """ Returns the current state of the button """ + + if self.__pin.value() == 0: + self.__button_down = False + return False + if self.__pin.value() == 1: + if not self.__button_down: + # print("button pressed") + self.__button_down = True + return True + else: + return False + +class Event(): + """ Models events that can happen, with timers and pop up messages """ + __name = "" + __value = 0 + __sprite = None + __timer = -1 # -1 means no timer set + __timer_ms = 0 + __callback = None + __message = "" + + def __init__(self, name=None, sprite=None, value=None, callback=None): + """ Create a new event """ + + if name: + self.__name = name + if sprite: + self.__sprite = sprite + if value: + self.__value = value + if callback is not None: + self.__callback = callback + + + @property + def name(self): + """ Return the name of the event""" + + return self.__name + + + @name.setter + def name(self, value): + """ Set the name of the Event""" + + self.__name = value + + + @property + def value(self): + """ Gets the current value """ + return self.__value + + + @value.setter + def value(self, value): + """ Sets the current value """ + self.__value = value + + + @property + def sprite(self): + """ Gets the image sprite """ + + return self.__sprite + + + @sprite.setter + def sprite(self, value): + """ Sets the image sprite """ + + self.__value = value + + + @property + def message(self): + """ Return the message """ + + return self.__message + + + @message.setter + def message(self, value): + """ Set the message """ + self.__message = value + + def popup(self, oled): + # display popup window + # show sprite + # show message + + fbuf = framebuf.FrameBuffer(bytearray(128 * 48 * 1), 128, 48, framebuf.MONO_HLSB) + fbuf.rect(0,0,128,48, 1) + fbuf.blit(self.sprite.image, 5, 10) + fbuf.text(self.message, 32, 18) + oled.blit(fbuf, 0, 16) + oled.show() + sleep(2) + + @property + def timer(self): + """ Gets the current timer value """ + + return self.__timer + + + @timer.setter + def timer(self, value): + """ Sets the current timer value """ + + self.__timer = value + + + @property + def timer_ms(self): + """ Get the timer in MS """ + + return self.__timer_ms + + + @timer_ms.setter + def timer_ms(self, value): + """ Set the timer in MS """ + self.__timer_ms = value + + + def tick(self): + """ Progresses the animation on frame """ + + self.__timer_ms += 1 + if self.__timer_ms >= self.__timer: + if self.__callback is not None: + print("poop check callback") + self.__callback + self.__timer = -1 + self.__timer_ms = 0 + else: + # print("Timer Alert!") + pass + diff --git a/lib/sdcard.py b/lib/sdcard.py new file mode 100644 index 0000000..cea5845 --- /dev/null +++ b/lib/sdcard.py @@ -0,0 +1,309 @@ +""" +MicroPython driver for SD cards using SPI bus. + +Requires an SPI bus and a CS pin. Provides readblocks and writeblocks +methods so the device can be mounted as a filesystem. + +Example usage on pyboard: + + import pyb, sdcard, os + sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) + pyb.mount(sd, '/sd2') + os.listdir('/') + +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) + os.mount(sd, '/sd') + os.listdir('/') + +""" + +from micropython import const +import time + + +_CMD_TIMEOUT = const(100) + +_R1_IDLE_STATE = const(1 << 0) +# R1_ERASE_RESET = const(1 << 1) +_R1_ILLEGAL_COMMAND = const(1 << 2) +# R1_COM_CRC_ERROR = const(1 << 3) +# R1_ERASE_SEQUENCE_ERROR = const(1 << 4) +# R1_ADDRESS_ERROR = const(1 << 5) +# R1_PARAMETER_ERROR = const(1 << 6) +_TOKEN_CMD25 = const(0xFC) +_TOKEN_STOP_TRAN = const(0xFD) +_TOKEN_DATA = const(0xFE) + + +class SDCard: + def __init__(self, spi, cs, baudrate=1320000): + self.spi = spi + self.cs = cs + + self.cmdbuf = bytearray(6) + self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) + for i in range(512): + self.dummybuf[i] = 0xFF + self.dummybuf_memoryview = memoryview(self.dummybuf) + + # initialise the card + self.init_card(baudrate) + + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + + def init_card(self, baudrate): + # init CS pin + self.cs.init(self.cs.OUT, value=1) + + # init SPI bus; use low data rate for initialisation + self.init_spi(100000) + + # clock card at least 100 cycles with cs high + for i in range(16): + self.spi.write(b"\xff") + + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) + for _ in range(5): + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: + break + else: + raise OSError("no SD card") + + # CMD8: determine card version + r = self.cmd(8, 0x01AA, 0x87, 4) + if r == _R1_IDLE_STATE: + self.init_card_v2() + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): + self.init_card_v1() + else: + raise OSError("couldn't determine SD card version") + + # get the number of sectors + # CMD9: response R2 (R1 byte + 16-byte block read) + if self.cmd(9, 0, 0, 0, False) != 0: + raise OSError("no response from SD card") + csd = bytearray(16) + self.readinto(csd) + if csd[0] & 0xC0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 + elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 + c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 + read_bl_len = csd[5] & 0b1111 + capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) + self.sectors = capacity // 512 + else: + raise OSError("SD card CSD format not supported") + # print('sectors', self.sectors) + + # CMD16: set block length to 512 bytes + if self.cmd(16, 512, 0) != 0: + raise OSError("can't set 512 block size") + + # set to high data rate now that it's initialised + self.init_spi(baudrate) + + def init_card_v1(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(55, 0, 0) + if self.cmd(41, 0, 0) == 0: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + # print("[SDCard] v1 card") + return + raise OSError("timeout waiting for v1 card") + + def init_card_v2(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(58, 0, 0, 4) + self.cmd(55, 0, 0) + if self.cmd(41, 0x40000000, 0) == 0: + self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte + ocr = self.tokenbuf[0] # get first byte of response, which is OCR + if not ocr & 0x40: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + else: + # SDHC/SDXC card, uses block addressing in read/write/erase commands + self.cdv = 1 + # print("[SDCard] v2 card") + return + raise OSError("timeout waiting for v2 card") + + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): + self.cs(0) + + # create and send the command + buf = self.cmdbuf + buf[0] = 0x40 | cmd + buf[1] = arg >> 24 + buf[2] = arg >> 16 + buf[3] = arg >> 8 + buf[4] = arg + buf[5] = crc + self.spi.write(buf) + + if skip1: + self.spi.readinto(self.tokenbuf, 0xFF) + + # wait for the response (response[7] == 0) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + response = self.tokenbuf[0] + if not (response & 0x80): + # this could be a big-endian integer that we are getting here + # if final<0 then store the first byte to tokenbuf and discard the rest + if final < 0: + self.spi.readinto(self.tokenbuf, 0xFF) + final = -1 - final + for j in range(final): + self.spi.write(b"\xff") + if release: + self.cs(1) + self.spi.write(b"\xff") + return response + + # timeout + self.cs(1) + self.spi.write(b"\xff") + return -1 + + def readinto(self, buf): + self.cs(0) + + # read until start byte (0xff) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + if self.tokenbuf[0] == _TOKEN_DATA: + break + time.sleep_ms(1) + else: + self.cs(1) + raise OSError("timeout waiting for response") + + # read data + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[: len(buf)] + self.spi.write_readinto(mv, buf) + + # read checksum + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + self.cs(1) + self.spi.write(b"\xff") + + def write(self, token, buf): + self.cs(0) + + # send: start of block, data, checksum + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + # check the response + if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: + self.cs(1) + self.spi.write(b"\xff") + return + + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def write_token(self, token): + self.cs(0) + self.spi.read(1, token) + self.spi.write(b"\xff") + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0x00: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def readblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, "Buffer length is invalid" + if nblocks == 1: + # CMD17: set read address for single block + if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + # receive the data and release card + self.readinto(buf) + else: + # CMD18: set read address for multiple blocks + if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + offset = 0 + mv = memoryview(buf) + while nblocks: + # receive the data and release card + self.readinto(mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + if self.cmd(12, 0, 0xFF, skip1=True): + raise OSError(5) # EIO + + def writeblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks, err = divmod(len(buf), 512) + assert nblocks and not err, "Buffer length is invalid" + if nblocks == 1: + # CMD24: set write address for single block + if self.cmd(24, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + + # send the data + self.write(_TOKEN_DATA, buf) + else: + # CMD25: set write address for first block + if self.cmd(25, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + # send the data + offset = 0 + mv = memoryview(buf) + while nblocks: + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return self.sectors + if op == 5: # get block size in bytes + return 512 + + +__version__ = '0.1.0' diff --git a/lightbulb.pbm b/lightbulb.pbm new file mode 100644 index 0000000000000000000000000000000000000000..91cdea788971a6a9730cca827c891212ccc3f865 GIT binary patch literal 87 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFZ7QD9(Df5IUkz#)7hfD1$laBv8ysIWg^f53bI0Q?yheOcKv@K!C?OnMA8lb02UG>*8l(j literal 0 HcmV?d00001 diff --git a/potty02.pbm b/potty02.pbm new file mode 100644 index 0000000000000000000000000000000000000000..29e3843d6c8d595bd7b08c15c9fb6179ef885c91 GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFh*9f%YFjWPt^UOprm44|srV#smByvVj>y_9P=nhzNviKMWFYZicI5 TIKU2MGyMMtBJ2NvNNfNAg7qJ1 literal 0 HcmV?d00001 diff --git a/potty07.pbm b/potty07.pbm new file mode 100644 index 0000000000000000000000000000000000000000..ef073fb30915ce3df227f1765a17d6c9c65839a1 GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFh*9;r1UuWPt^UOprm44|srV#smByvVj>y_9P=nhzNviKMWFYZicI5 QIKU2MGyMMtBJ2ME00G_~X#fBK literal 0 HcmV?d00001 diff --git a/potty08.pbm b/potty08.pbm new file mode 100644 index 0000000000000000000000000000000000000000..17b090d312ad4a98e42a9ec7c93841d88883695d GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFh*9;r1UuWPt^UOprm4FLZ!x#v}e9vVj>yb|{0$ImHN(=4KGP#Ti7l TABKxF9AF2s8UFtRk@bH7AZQ=; literal 0 HcmV?d00001 diff --git a/potty09.pbm b/potty09.pbm new file mode 100644 index 0000000000000000000000000000000000000000..c1e47f4baee3d1c3afdd3dfa4c93f6d9bf51f698 GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFh*9f%YFjWPt^UOprm44|srV#smByvVj>y_9P=nhzNviKMWFYZicI5 UIKU2MGyMMtBJ2Nv+5a&~0M?-=VE_OC literal 0 HcmV?d00001 diff --git a/potty10.pbm b/potty10.pbm new file mode 100644 index 0000000000000000000000000000000000000000..d3e706ca31a0c7fec72067fa360ebce2fef43934 GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFHk0?|G}DJBmhzSE&2ce literal 0 HcmV?d00001 diff --git a/potty11.pbm b/potty11.pbm new file mode 100644 index 0000000000000000000000000000000000000000..499d2ce539be6b86385306f84cd4b17de25937c2 GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFcfk@^9Ad(+!lr+d#2J=54 NGW{Qj{Qn=B1OQqLD!~8% literal 0 HcmV?d00001 diff --git a/potty14.pbm b/potty14.pbm new file mode 100644 index 0000000000000000000000000000000000000000..ccb7c9141f24240fc127ca00eab56c705af7888e GIT binary patch literal 343 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFeOcKv@K!C?OnNF;z*5)e`X#Abt#5D^Fo5@rBf#K3$2#D=&}8tgvvKOm8GkXa1> I!REq90GbFf+W-In literal 0 HcmV?d00001 diff --git a/raw_assets/baby_zzz01.xcf b/raw_assets/baby_zzz01.xcf new file mode 100644 index 0000000000000000000000000000000000000000..f5106d2678f762e3147db86b12b65afc1bed31a3 GIT binary patch literal 1069 zcmb7@xlY4C5Qf(WgoJP(6@m?ylETQYD3NHWsHmurZ5(5f*ioDyQiT^lqT(rd5MGCZ zdilrRkrs)DvHqQJW_H)!Svk#yBl#Tn<&z%-0_JO3@bAzDWKpmMEnU6|L4s{VF62PF znrYq+^a-t}*xJj6VVZd9IJ-wmQ2nD@PG*Bdmc<~u@3p%9G%g0kSavJtjngQUe)R-B zl%qe&fvg@XKbNC0&hk_SKBC#LNC)0D&n7a<aCKFlBH@L>%lj)lcv#yK) z=$sodH_k?GGYX^GT~ti-IPrtCQ8c89R3Tf0sB;SH5MR7tM0X*|Qz$SJVmgyINhYs@FcgSD!vg;UJ^>ab`@q)OUm*yH z1HjezqM7D>1|ERj9Iy6^X_TjaJ}<_w1l8|{^vK6S~{8YKFL z{%Yv9p{1ce7`kKVkA~iXru{ft5VSYF|4?g?_)c0Ozym|`?em#XqOgB%xEZ-4bRLAg z+;B5;jr>3CukAbK3Ll$2!xa~*C61IQEciWTi+8|4S)v8*YbJjST7o_0h;PsxfY^d( z1D4L&|DPS~?YuIl3$Km!UA2w8nu5XY$x+p*&&Y1(EgYAQ(!dr%<_nS*xeRCLIcDUcLd5n@Y*Wf$?}zCeIX zeTqIv->C!hKZ*y?K$f2H=lyuc5An#NoG;`yn*(tCw=DUAQdL zL`M3HCrGC+q+_W+N#AJIvdZrAhGx{$X_K#{9&d4ryMyVU zEpxtE9iaEa>T}^-#E#P>-Q1-0y2|n>{=7)%G>|f6U5F~Dpn&-D7g|&oqBvElZx~LT zTKwMPfyL6|eT#<{zq0rcO#89*0JJx)|IsjWFjY>R6z9!UK;~U&lJ&Gv$aL{HgH)cn>V$`^pm^z(a_< zgP03Brq6NqUF_|foTvWbiWK&1=b{XvYt0*h2Uu&Q4n&}aV(SJ}B|h2VRX)qJRasZ^ zd(zy~8L7Zz`~bG#_5tYde?I_;X}sovVJh|!g%yySv{dQBmHhz-shch;R;*Yd+i{FVVn=a;npOG(mAdLT zbkPstuP$etJJKz5!?BLfnVEZS-x=q{Y_6`;iTV{r5dop01HA_iL5G9a;O@m85feB9 zeQ*bSYdo)e1O5gNay&XHW^tYc`JxyjMO=Rz)ywrXQ*|{h#%JBpBu}epwNRr*f<>Oh zDr~Ok4CUmRa-^Dz%h&ZhPKz>EQHW^$Br-v;DvPBm%JfH8^NwmVsk5bO)?0pSpDyNa zw%}Y^0jzgr#nLzzxmQV?tiLDKs!X#mI-e&qUdRw%XjKBYYmf zU2V0wOO5lllHWKFx!sqWB;c4-GZ)(*9yL!$%uU3dlUVDAU` z9?0q-=Yo!jCI7d2+9&UsHGSl|*x%QCG|)ZTxC8ExoNE7THqFvyQI+aTT>s?radR0m z{0;ne_)Yr1hp(_rp1Ef{H~IkdK;RVQ`P-1WnVCq*=l@N<-qd{l4+K&}?0=HvrbGG< DGiIN} literal 0 HcmV?d00001 diff --git a/raw_assets/baby_zzz05.xcf b/raw_assets/baby_zzz05.xcf new file mode 100644 index 0000000000000000000000000000000000000000..154b80d7acf4734369b6774c8f5fee55b5de5595 GIT binary patch literal 1101 zcmb7EJ8s)R5FLI@S&HIMepOuvcK}u$(4E9v1WR93kTT{is>2Cb??rNqK(S8;y&sp44+SYAKu- zX`-U`iBFME|B;SW`*8ZQnI&0S6)KM4t)6(s371v5P-T@}#OBE2n`0>rYo`QC)!JT&1qj zAR1cwy`_7WR+fHY>At03T6!0n*AweN@Y+28N25V>%v!_1N0ye;mpviH=KkDp+e$@v zKQMQ>;kK0=$FC*6cJ6dQAr^a%fQH($;vRj_9XionI@T_20Y}=Q4tQvI0KE;Zz+H?z zfbIj#4q`6g7+>PT*fIqs=jjI=l_t;l0dl@I?hv|%xeoOX4RoK@?trT$JKX)APx5S0 z)|L8}G{1STTxd4A2y5ugMQFqSeGwFf$(%bzbJ6zz4}hHjd>3q!Gc@NTDWAV!d3%%d S+kb=UAvw7IR~fbLl70lryQbm* literal 0 HcmV?d00001 diff --git a/raw_assets/bubble.xcf b/raw_assets/bubble.xcf new file mode 100644 index 0000000000000000000000000000000000000000..13fa5e94506e0b536ca2389ad89d066749437918 GIT binary patch literal 725 zcmZva%SyvQ6o!)`UV6cLUAY)<&@KYa69`ri7lN;lrpa`$NlKDx3kBVYFW?Kf^$mP1 zw?h5@X$Gd?8U8unx#V^-QY8~H3uE!r^L+=_u2h5nfLy2!FurHk0uIs z2yH-YJ+7F2N6-({l6aUGW=RsIC1QQ={eB(=Wi%AesvL>iyZZ-L+PYOGfs8zvtD))s z>J;UC9Elx&*cv{jnis76KGENEK_1t3n qWFT#<_GSp)jDp_-t9`D#-c619Z^aY3_9xE2+CAEv7<^+{kag8)hjHR@xnu1!11xH}TDL4oxs#qYI zf1FsFN=*7^zIphOsW$Va+N8O99mlbN4H^aTpU^23P;dryA3ua3!Oo!rNJ5tlQ{M&j z4GlE5j?6sKS)^BHhLoWC*RWb|i%eBzVP>QLFxP2Wlq)rKE?VhnqQ>rtM<`GKDaXn^ zRNhp}BsB}I;xVG_UepB9%fhUcS)|WdMJviYud=mr{fukeZ>Bpl3nnb^=m$n~=%q14bh-1bWJ>Y#~Z_hC{IJ_H4Glt-@DaT7DSQwg%4Geg z>?VV8n!oeSp*!tV>BUNJvr@iJlSIJARv!E(bP9PCoI!)f4vZ*VbPli#cvbw6*GHPACR`XO&+bfx%JpZSh$o8W0 zwppc_UMiVP5$z5l8^kY5y^(sEJr@ljP*uoqul` zPTUb282l|`{v4C<*!>{c^d^6IB*@HW_sLsg8@hSg3wQ!9tHCHLR|10DJt89jfZ0 zy(;HXoXxZfhsf4DS)Bw=vuvrdS^SukTv4QHnJiV+@93@EZRR^W;fl{j_)*x}^=nF@89jzR_@8|>tPq{F1*MA!`wJ>XVuu93;5v@6n#PfxqGlDAELpK;$$}MM z!HN~%(0#vPIA=T~O{=V`3UQ+|=iG}J?{lwZVII?Bp?f{-mk#FNwTC%|B0&4ypg#SC zwXR{Djq3u`v_rt^=Z@|f&3fs?w;bJf^tPiPLGw(~pbh3bxc^I|LE@NN!N5n3wikl` z%`t!GIJP;a5B}#3IfVRgHoo?RBH-I++1P!zu`($ZD?aehUF4n;u$}&wT{O3YN1z2i zYu2mngy~}Ndqa-TT-$g@d7=#jhMRYM?~cC*zpnz(Rc+CNR;q=OlRLr(d#VflTCD5I zgm@3Z^K6ad2M*RipS;=+) literal 0 HcmV?d00001 diff --git a/raw_assets/potty02.xcf b/raw_assets/potty02.xcf new file mode 100644 index 0000000000000000000000000000000000000000..e22286fe78e886dee1f52e0f472e901d5fa198c8 GIT binary patch literal 1214 zcmd6l%}(1u6otn>|2y|l>sC<(4Vcgx9qn8-38X8n^^caX;UFfU}cvR;v1 zM>43c@C3`(E0#l9U0j}(<0#HXsSE>T^ADL$dec!hk=ZD|NlN}A9}LQ5BCGutFY)7M zzOxn1#WHbUt)jtA0Odj3zoK%I^yO7FPYN05<2iS^ydi23JEx!y`RpF|WhYr@mzofn zaR3?qVR6f1Y4N(nZHvEHyaDFqq*fiyXYl-=nqlIItPt=+i|y&7Y{LC*2yQx}|F=6` zv4)cSVCoI!h&tqHU;C6hpYko_ZRLrks*4&}sTy9E-ViR_QBClvSfGSw1X_Hb_46qH zlNR}O)aTRxr;+e|82>sF^O-GA5#E~ynrQ()F@(=gz=T;t?n_f#xR+?|F&cTKT(Jfn zqOo=Of%XoVgOl(khOq~3Lv#+oXjN|Z8TXW54WD~`oX26B^Y+0l)b`a^(NS%&@b1(* Djd!uP literal 0 HcmV?d00001 diff --git a/raw_assets/potty03.xcf b/raw_assets/potty03.xcf new file mode 100644 index 0000000000000000000000000000000000000000..804bbeb6890fbc5a1bf85ebb3ba7c8995ef98c0f GIT binary patch literal 796 zcmZvZOK!q25Qd#c%d;=_v8sxBw1P#X z1&;R8MJQrV6zL2lM*W{*x!TTSUgq<3HfjzN5#{r|;KRziLQF&MS5GiPdwQZB@am!V zrd)VM66z9<_gFDbi0U+!hGH1&8T@E)(_n6J%iy-b7Y1K}>3ceA0Qxqa z|Ew6s2E-Bp?;EWDZha@TDD2mRSF0Wc-3MVO2d`G$qxz?=@2p>0V=uD72GV9{P+wZC z2Jb2Fg6m)oZ%Btdf!h$dZRk|4_i1;e%N+Hti}PH?)bBt|)H?E#b!D6FTu1%`(*J?4 literal 0 HcmV?d00001 diff --git a/raw_assets/potty04.xcf b/raw_assets/potty04.xcf new file mode 100644 index 0000000000000000000000000000000000000000..ddebf739db2d10c83f00ee84384394f024b40bcd GIT binary patch literal 796 zcmZvZOK!q25Qd#c%d;=_v8sxBw1P#X!&Z_HDiGoH%qmodUc>IACN)1(?34qXwXF z)A^5zVQfGw5%9jj`tR0vLW{zF-g~v`QP6!5cCz-x_6lQs4v8*CtLb^`UK z#cJ@L@-Daz=J1Ae*aNr?k=urj<$9lXN4m^W@47h8RZRU3)I_Z#&skTt+0OZu|Mhr+ At^fc4 literal 0 HcmV?d00001 diff --git a/raw_assets/potty05.xcf b/raw_assets/potty05.xcf new file mode 100644 index 0000000000000000000000000000000000000000..f1ac2bac04a9c9d66b4a169e11a5c68f46573596 GIT binary patch literal 796 zcmZvZS#H8G5Qd$lW$mUePgOBXD|m>MoB)ZZs<#LsaicVM66z9wQP?kguU0(@x(~um_Fk>JNA*u#-#H($#-3z@4W!LZpuV(N z4c=4U1=qnG-jEJ^0JkA>+t9IG@6+x`mpSTP7w5T(so#N`sCDEy>&iCU+0XJHsB7@am!V zwp@i#nh75G$aY7WO1w>$u6de8uW?Cl zqR2N{bzLe^(1>VM66z68KCxn)5Y=fcO~o+QH~7KemciWMw!s~P&keo=)Aw}L0rYJ; z|4A{74T&WJJ}_AS-TF>wQP?jBuU0(@x(~um4qmOgNA(X~-`5;jXV0?9hSFv=Xdo?C zhxe8Dzzr~mH>JZK!5xU)Hgqc2`?NdKWsZ8+#d)q`>UW_QYF&B3da}dz>{tE+Vu69L literal 0 HcmV?d00001 diff --git a/raw_assets/potty07.xcf b/raw_assets/potty07.xcf new file mode 100644 index 0000000000000000000000000000000000000000..eacb424a9d6a3d4f44d9bd500baa69e4b1aff53d GIT binary patch literal 794 zcmZvZOK!q25Qd!)%Cj%^v8sxBw1P#X27$YIBArCr%ZZ*@s8|V+Z z5IEYGt4JiiDC7bqM*W|0xp`YAyv&z!F=>xe5$DUi;N!~tLd+u`R8KfTdw!%H^6H`X zu3Sg4%mfbuWN!zVPW){qH(X}%b5hb9d775VhFAM7-s9nB`ps52Q!6oO2IivBnMLu7 zDDrJqU6)D}G$I<6g8IbMPplXxM0FZVOEZiOEWWe2Z85jFV{zBwQ;W~R^gR;|0DYUz zf6xqLBVvVs4=px-x49Eq6z$7 x0Uv1ZgPULuZ>bu)2X`TI*V3`v>@!|d9;@khJ)GxhrhX4v;^}Dp=rm;0&-RIR_3WZ;TNT7k~pC09Q&=-zD$` zoW|IClq~!>9L0GugT<)+F(_8sdB}@wp3H`gK@%o`wd;n{bo9|5!Tp9wA2H$VKgUx z@EGUWI+fQYi-JZ(qY^-e^!ODk#tD#5W2q|*VqHUD8@gd=Zs?|=TZTR|^a(V5Pe%=c zzD@hzDh*Y#?fr?!-S}?8+5e*V)AitaG6`O*JhT=b)N&@QC>y%3s%|X T&Q4Q*8)%@vEsj}7w6ND7)>e=V literal 0 HcmV?d00001 diff --git a/raw_assets/potty09.xcf b/raw_assets/potty09.xcf new file mode 100644 index 0000000000000000000000000000000000000000..6317d4e779a8b7b17c87cda0ff1357d6172035b3 GIT binary patch literal 808 zcmZvZ+fKqj5Qeu0`F4TnXDyDt6&@Xf; zaI}}MLJ@nSNEawE>i>+(&3+m4GGC^PNo$;lC|~9UA1m_;F%P+~o?wFZ{6st8>Y?_o zT!&Gb2_E>!_D5Njc-t)9@HC5F;*#FTlcbC{T`6A+NZPCh4W-5E z@ImE$a0ATYP3f=)a0eo{4V}vMKJAWlnNz*%;ykxv>i3`)YCU;WE~eV~2uSA>8a z00Gbi-WttyZ-6IYH^rw%*>#jAqqNK>2nq8KgKEB*C8{cB*<{!qOw+iS6{Q-~G%C}p zNR8_!93p+SCLOB!VfwDRiQ+6zRXB#Xc;Ojmbem^$mF4lbq~eZZI<1nqs@FSuC0{OP z&5n7OE64xh1g*43i+0&JNE`qbyY@J3q!#@U{Z(I7c;^gBnh zjTHqtYedso{0(Z18@1c7Dx#3`)Z`WD&bs)ak8{m6^ z(aawLUBnLcw)AyRmhyO;ky4*VTEbTIn6^SOI6+HSob(pQCD?Ow^}n zk(4~||8xly>LLF167V8A7JPLa+XQn_f@)0;q2P~=bG$8pqakm+^1WC79{e5#)4^bx T&>Rd$$-(eSa4=e*$r7Pwpt8P9 literal 0 HcmV?d00001 diff --git a/raw_assets/potty11.xcf b/raw_assets/potty11.xcf new file mode 100644 index 0000000000000000000000000000000000000000..56cc6edbe108a9b0a90791c6752f0074c36ae160 GIT binary patch literal 1209 zcmd5)%TC)s6dgavI}`+E(+Va8P*_CRUx37>n=ZQO4>*ovEJ7UF0g+X@?6RwVML(pQ z{sj`hz-~ClnUMyRRaac=_?-L5_2k}3v)j3Rh$r$s2txr2G#v16U>9)c>;a9dUqTSD zeZU9Wz=77R`w096c2cw+X17tA4AUYTBP5vrGbk6!X(G#fnvKs}gGn0a)4Y&_iiSlx zieykd;W^Ty4e3x;57Q6jJc_efD#HNY@|CBZ;oU4-$ZQs0CnbN8PbOuukX5~<*Yb5S z&up3VW$n0+R?x^D2*Lxp-=cDnjOEv8nG`H=`GVB|4ov|)>dPN^W3T|@98gnhkT|yV zXG^y%EiKJuun(;R7~Qq>2WWmzYSh83WB*gFLE?m3!N7e>o5iz-W$t&&F~iXR+nsO7 zA>{rv@rH6l9q=@7z44tl{x1BE@_n^5r32tH;htM5>%q19X@=cv#Px;mIS?i-8mudPPLAMY)Qrn`ZI%4JhQ!fpC Bu(kjI literal 0 HcmV?d00001 diff --git a/raw_assets/potty12.xcf b/raw_assets/potty12.xcf new file mode 100644 index 0000000000000000000000000000000000000000..671a59bb63e7b6bf77ab36a93e70224d0622058c GIT binary patch literal 1230 zcmb_a%TC)s6dgbEByD+CT~uWP6oo~E{RK#D*s$OijN`agLmb%wkyY5RXVqQ*pkL7y zzl4M|oMX>O1InhT*E(~~y>oqMbnm3u)lA;TV|f#Vp@0P%4)_{JT8;Dtnw{g%h$=g zvt`a%?YK`?(8zTN!UHxhqH>;${OdchB|)a<1J|yB;X4)>C(5L6vl}Z8la}#7$3ovPvL|3Om4>i zP$o_j5Bzh!a~T*8QY}|vlVsvGj3Ndbb>i@!&?&?zID-ynAB>S;=THxFpv#V_?*jUU zMiP$>)H0T7AS<;%ic$S*TsPZ16?K`b#bhwfWK!m3CC04_Dmjlu*j~{D<@rD5NVFG~ zH}xt`R3SwaBHHdnT@b7b)d*E2&uL9N$}FqXMzsAF?{L4F&TJW_Gd>(L<*7BXc!}dN=@w bTrla1an!l)qi2X-AA30a!3lADf9UF8ZW?aN literal 0 HcmV?d00001 diff --git a/raw_assets/skull02.xcf b/raw_assets/skull02.xcf new file mode 100644 index 0000000000000000000000000000000000000000..9e3a7c2b4fcaebe78f301707b1b8a918cd0bd0eb GIT binary patch literal 694 zcmZvZOKyWO5QYtDLmP^ks*hC{?n_D*NN|EkS@sr$fNPaN1SCo}RgchBPtk+)Ox?Ku z7_2%{$NZjeW{iyoAy;d@OLM-B;+Vn4y&U*Y=mK&mxP(sTAB>S;SI`kOfNpxGb=S~0 zG#1!8l&eH!p{V5&DMt0LNz?9&j5k#wm($TC7im>gHJ@k~)?$(HNRN1m^5UOz%=Mu1 zu30CkECr7vMEirN55i3;TQ1A=C2Q!7D$kp&<$Arv9Ud;GZ??>tS%E>*Fc%4bo}{m$ zt~RBd1}jP&v5MC;#-SH7ITYzi_a_$EItR*dB!{dolW~c z^$f=zi4_d~!D92f&7DvpbDuk}XVVJ056sOwuV+)E{F})Sl*f*h&s-HSrMAq0chnFZ RAm^jzupfL09`6qa>KC~>Xx#t+ literal 0 HcmV?d00001 diff --git a/sdcardtest.py b/sdcardtest.py new file mode 100644 index 0000000..6729547 --- /dev/null +++ b/sdcardtest.py @@ -0,0 +1,104 @@ +import machine +import sdcard +import uos +import json + +mytestdata = { + "health":11, + "happiness":1, + "energy":1 + } + +# Create a file and write something to it +#with open("/sd/test01.txt", "w") as file: +# file.write(json.dumps(mytestdata)) + +# Open the file we just created and read from it +#with open("/sd/test01.txt", "r") as file: +# data = file.read() +# print(data) +# varx =json.loads(data) +# print(varx["health"]) + +class SaveGameManager: + __SaveGameData = {} + __FileSocket = None + __cs = None + __spi = None + __sd = None + + def __init__(self, savename="01"): + print("initializing") + try: + # Assign chip select (CS) pin (and start it high) + self.__cs = machine.Pin(9, machine.Pin.OUT) + + # Intialize SPI peripheral (start with 1 MHz) + self.__spi = machine.SPI(1, + baudrate=1000000, + polarity=0, + phase=0, + bits=8, + firstbit=machine.SPI.MSB, + sck=machine.Pin(10), + mosi=machine.Pin(11), + miso=machine.Pin(8)) + + # Initialize SD card + self.__sd = sdcard.SDCard(self.__spi, self.__cs) + + # Mount filesystem + self.__FileSocket = uos.VfsFat(self.__sd) + uos.mount(self.__FileSocket, "/sd") + + #load values from FS + self.LoadSaveData() + except: + pass + + + + @property + def CheckFilesystemReady(self): + if self.__FileSocket is None: + print("No FileSocket") + return False + return True + + def LoadSaveData(self): + print("loading") + # Open the file we just created and read from it + if not self.CheckFilesystemReady: + return # If we have no filesystem we cannot write or read anyways... + + with open("/sd/test00.txt", "rb") as file: + file.read(1) #ignore first byte, it containes the version number as binary... later :) + data = file.read() + self.__SaveGameData = json.loads(data) + + def WriteSaveData(self): + if not self.CheckFilesystemReady: + pass # If we have no filesystem we cannot write or read anyways... + # Create a file and write something to it + with open("/sd/test01.txt", "wb") as file: + file.write("0") + file.write(json.dumps(self.__SaveGameData)) + + def UpdateData(self, key, value): + print("updating internal data") + self.__SaveGameData[key]=value + + def GetData(self, key, defaultvalue=""): + print("getting internaldata") + if key in self.__SaveGameData: + return self.__SaveGameData + return defaultvalue + + +mysavegame = SaveGameManager() +mysavegame.UpdateData("bla","blub") +mysavegame.WriteSaveData() +mysavegame.LoadSaveData() +print(mysavegame.GetData("bla")) +print("x:"+mysavegame.GetData("something")) +print("x:"+mysavegame.GetData("something","defaultthing")) \ No newline at end of file diff --git a/skull01.pbm b/skull01.pbm new file mode 100644 index 0000000..b860ad3 --- /dev/null +++ b/skull01.pbm @@ -0,0 +1,4 @@ +P4 +# Created by GIMP version 2.10.22 PNM plug-in +16 16 +ð?üþÿÿÿÿÿÿá‡ÁƒÃÃÿÿþþþ?ü ° ° \ No newline at end of file diff --git a/skull02.pbm b/skull02.pbm new file mode 100644 index 0000000..219ddb7 --- /dev/null +++ b/skull02.pbm @@ -0,0 +1,4 @@ +P4 +# Created by GIMP version 2.10.22 PNM plug-in +16 16 +ð?üþÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþ?ü ° ° \ No newline at end of file diff --git a/ssd1306.py b/ssd1306.py new file mode 100644 index 0000000..1bb6679 --- /dev/null +++ b/ssd1306.py @@ -0,0 +1,155 @@ +# MicroPython SSD1306 OLED driver, I2C and SPI interfaces + +from micropython import const +import framebuf + + +# register definitions +SET_CONTRAST = const(0x81) +SET_ENTIRE_ON = const(0xA4) +SET_NORM_INV = const(0xA6) +SET_DISP = const(0xAE) +SET_MEM_ADDR = const(0x20) +SET_COL_ADDR = const(0x21) +SET_PAGE_ADDR = const(0x22) +SET_DISP_START_LINE = const(0x40) +SET_SEG_REMAP = const(0xA0) +SET_MUX_RATIO = const(0xA8) +SET_COM_OUT_DIR = const(0xC0) +SET_DISP_OFFSET = const(0xD3) +SET_COM_PIN_CFG = const(0xDA) +SET_DISP_CLK_DIV = const(0xD5) +SET_PRECHARGE = const(0xD9) +SET_VCOM_DESEL = const(0xDB) +SET_CHARGE_PUMP = const(0x8D) + +# Subclassing FrameBuffer provides support for graphics primitives +# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html +class SSD1306(framebuf.FrameBuffer): + def __init__(self, width, height, external_vcc): + self.width = width + self.height = height + self.external_vcc = external_vcc + self.pages = self.height // 8 + self.buffer = bytearray(self.pages * self.width) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + self.init_display() + + def init_display(self): + for cmd in ( + SET_DISP | 0x00, # off + # address setting + SET_MEM_ADDR, + 0x00, # horizontal + # resolution and layout + SET_DISP_START_LINE | 0x00, + SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 + SET_MUX_RATIO, + self.height - 1, + SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 + SET_DISP_OFFSET, + 0x00, + SET_COM_PIN_CFG, + 0x02 if self.width > 2 * self.height else 0x12, + # timing and driving scheme + SET_DISP_CLK_DIV, + 0x80, + SET_PRECHARGE, + 0x22 if self.external_vcc else 0xF1, + SET_VCOM_DESEL, + 0x30, # 0.83*Vcc + # display + SET_CONTRAST, + 0xFF, # maximum + SET_ENTIRE_ON, # output follows RAM contents + SET_NORM_INV, # not inverted + # charge pump + SET_CHARGE_PUMP, + 0x10 if self.external_vcc else 0x14, + SET_DISP | 0x01, + ): # on + self.write_cmd(cmd) + self.fill(0) + self.show() + + def poweroff(self): + self.write_cmd(SET_DISP | 0x00) + + def poweron(self): + self.write_cmd(SET_DISP | 0x01) + + def contrast(self, contrast): + self.write_cmd(SET_CONTRAST) + self.write_cmd(contrast) + + def invert(self, invert): + self.write_cmd(SET_NORM_INV | (invert & 1)) + + def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width == 64: + # displays with width of 64 pixels are shifted by 32 + x0 += 32 + x1 += 32 + self.write_cmd(SET_COL_ADDR) + self.write_cmd(x0) + self.write_cmd(x1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + self.write_data(self.buffer) + + +class SSD1306_I2C(SSD1306): + def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): + self.i2c = i2c + self.addr = addr + self.temp = bytearray(2) + self.write_list = [b"\x40", None] # Co=0, D/C#=1 + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.temp[0] = 0x80 # Co=1, D/C#=0 + self.temp[1] = cmd + self.i2c.writeto(self.addr, self.temp) + + def write_data(self, buf): + self.write_list[1] = buf + self.i2c.writevto(self.addr, self.write_list) + + +class SSD1306_SPI(SSD1306): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): + self.rate = 10 * 1024 * 1024 + dc.init(dc.OUT, value=0) + res.init(res.OUT, value=0) + cs.init(cs.OUT, value=1) + self.spi = spi + self.dc = dc + self.res = res + self.cs = cs + import time + + self.res(1) + time.sleep_ms(1) + self.res(0) + time.sleep_ms(10) + self.res(1) + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(0) + self.cs(0) + self.spi.write(bytearray([cmd])) + self.cs(1) + + def write_data(self, buf): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(1) + self.cs(0) + self.spi.write(buf) + self.cs(1) \ No newline at end of file diff --git a/toilet.pbm b/toilet.pbm new file mode 100644 index 0000000000000000000000000000000000000000..07efcb391cdf8b8c2b2a95b6c65216edcf904ffe GIT binary patch literal 87 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW(la#BGcr;L@bgtD$SFYaU;tqVEdEjchk?QVhy4%v5Bv}K8~7UlHNF|_ literal 0 HcmV?d00001 -- 2.47.3