def run(): # some SD cards won't work in 4-bit mode unless freq() is explicitely set freq(240 * 1000 * 1000) # 80/160/240 MHz, faster CPU = faster SD card #sd=SDCard(slot=3) # 1-bit mode sd = SDCard() # 4-bit mode mount(sd, "/sd") print(listdir("/sd")) f = open("/sd/long_file.bin", "rb") # any 1-10 MB long file b = bytearray(16 * 1024) i = 0 t1 = ticks_ms() while f.readinto(b): i += 1 t2 = ticks_ms() print("%d KB in %d ms => %d KB/s file read" % (i * len(b) // 1024, t2 - t1, 1000 * i * len(b) // 1024 // (t2 - t1))) f.close() umount("/sd") i = 0 t1 = ticks_ms() while i < 256: sd.readblocks(i, b) i += 1 t2 = ticks_ms() print("%d KB in %d ms => %d KB/s raw sector read" % (i * len(b) // 1024, t2 - t1, 1000 * i * len(b) // 1024 // (t2 - t1))) sd.deinit()
async def play_wav(): bck_pin = Pin(21) ws_pin = Pin(22) sdout_pin = Pin(27) # channelformat settings: # mono WAV: channelformat=I2S.ONLY_LEFT audio_out = I2S( I2S.NUM0, bck=bck_pin, ws=ws_pin, sdout=sdout_pin, standard=I2S.PHILIPS, mode=I2S.MASTER_TX, dataformat=I2S.B16, channelformat=I2S.ONLY_LEFT, samplerate=SAMPLE_RATE_IN_HZ, dmacount=10, dmalen=512) # configure SD card # slot=2 configures SD card to use the SPI3 controller (VSPI), DMA channel = 2 # slot=3 configures SD card to use the SPI2 controller (HSPI), DMA channel = 1 sd = SDCard(slot=3, sck=Pin(18), mosi=Pin(23), miso=Pin(19), cs=Pin(4)) uos.mount(sd, "/sd") wav_file = '/sd/{}'.format(WAV_FILE) wav = open(wav_file,'rb') # advance to first byte of Data section in WAV file pos = wav.seek(44) # allocate sample arrays # memoryview used to reduce heap allocation in while loop wav_samples = bytearray(1024) wav_samples_mv = memoryview(wav_samples) print('Starting ... ') # continuously read audio samples from the WAV file # and write them to an I2S DAC try: while True: num_read = wav.readinto(wav_samples_mv) num_written = 0 # end of WAV file? if num_read == 0: # advance to first byte of Data section pos = wav.seek(44) else: # loop until all samples are written to the I2S peripheral while num_written < num_read: num_written += audio_out.write(wav_samples_mv[num_written:num_read], timeout=0) await asyncio.sleep_ms(10) except (KeyboardInterrupt, Exception) as e: print('caught exception {} {}'.format(type(e).__name__, e)) raise finally: wav.close() uos.umount("/sd") sd.deinit() audio_out.deinit() print('Done')
class SD: def __init__(self, miso=PIN_MISO, mosi=PIN_MOSI, sck=PIN_SCK, cs=PIN_CS, sd_path=SD_PATH): self.miso = miso self.mosi = mosi self.cs = cs self.sck = sck self.sdcard = None self.sd_path = sd_path self.inited = False self.mounted = False def start(self): try: self.sdcard = SDCard(slot=2, miso=Pin(self.miso), mosi=Pin(self.mosi), sck=Pin(self.sck), cs=Pin(self.cs)) self.inited = True self.mount() except Exception as e: sys.print_exception(e) print('sd init failure') def mount(self): try: os.mount(self.sdcard, self.sd_path) self.mounted = True except Exception as e: sys.print_exception(e) print('sd mount failure') def stop(self): if self.mounted: self.mounted = False try: os.umount(self.sd_path) except Exception as e: sys.print_exception(e) print('sd umount failure') if self.inited: try: self.sdcard.deinit() except Exception as e: sys.print_exception(e) print('sd deinit failure')
class SD: def __init__(self, slot=2, pin=4) -> None: self.sd = SDCard(slot=slot, cs=Pin(pin)) def __del__(self): self.sd.__del__() def deinit(self): self.sd.deinit() def mount(self, path="/sd"): mount(self.sd, path) def umount(self, path="/sd"): umount(path)
class FTP_client: def __init__(self, ftpsocket): global AP_addr, STA_addr self.command_client, self.remote_addr = ftpsocket.accept() self.remote_addr = self.remote_addr[0] self.command_client.settimeout(_COMMAND_TIMEOUT) log_msg(1, "FTP Command connection from:", self.remote_addr) self.command_client.setsockopt(socket.SOL_SOCKET, _SO_REGISTER_HANDLER, self.exec_ftp_command) self.command_client.sendall("220 Hello, this is the ULX3S.\r\n") self.cwd = '/' self.fromname = None # self.logged_in = False self.act_data_addr = self.remote_addr self.DATA_PORT = 20 self.active = True # check which interface was used by comparing the caller's ip # adress with the ip adresses of STA and AP; consider netmask; # select IP address for passive mode if ((AP_addr[1] & AP_addr[2]) == (num_ip(self.remote_addr) & AP_addr[2])): self.pasv_data_addr = AP_addr[0] elif ((STA_addr[1] & STA_addr[2]) == (num_ip(self.remote_addr) & STA_addr[2])): self.pasv_data_addr = STA_addr[0] elif ((AP_addr[1] == 0) and (STA_addr[1] != 0)): self.pasv_data_addr = STA_addr[0] elif ((AP_addr[1] != 0) and (STA_addr[1] == 0)): self.pasv_data_addr = AP_addr[0] else: self.pasv_data_addr = "0.0.0.0" # Invalid value def send_list_data(self, path, data_client, full): try: for fname in uos.listdir(path): data_client.sendall(self.make_description(path, fname, full)) except: # path may be a file name or pattern path, pattern = self.split_path(path) try: for fname in uos.listdir(path): if self.fncmp(fname, pattern): data_client.sendall( self.make_description(path, fname, full)) except: pass def make_description(self, path, fname, full): global _month_name if full: stat = uos.stat(self.get_absolute_path(path, fname)) file_permissions = ("drwxr-xr-x" if (stat[0] & 0o170000 == 0o040000) else "-rw-r--r--") file_size = stat[6] tm = localtime(stat[7]) if tm[0] != localtime()[0]: description = "{} 1 owner group {:>10} {} {:2} {:>5} {}\r\n".\ format(file_permissions, file_size, _month_name[tm[1]], tm[2], tm[0], fname) else: description = "{} 1 owner group {:>10} {} {:2} {:02}:{:02} {}\r\n".\ format(file_permissions, file_size, _month_name[tm[1]], tm[2], tm[3], tm[4], fname) else: description = fname + "\r\n" return description def send_file_data(self, path, data_client): with open(path,"rb") as file: chunk = file.read(_CHUNK_SIZE) while len(chunk) > 0: data_client.sendall(chunk) chunk = file.read(_CHUNK_SIZE) data_client.close() def save_file_data(self, path, data_client, mode): with open(path, mode) as file: chunk = data_client.recv(_CHUNK_SIZE) while len(chunk) > 0: file.write(chunk) chunk = data_client.recv(_CHUNK_SIZE) data_client.close() def get_absolute_path(self, cwd, payload): # Just a few special cases "..", "." and "" # If payload start's with /, set cwd to / # and consider the remainder a relative path if payload.startswith('/'): cwd = "/" for token in payload.split("/"): if token == '..': cwd = self.split_path(cwd)[0] elif token != '.' and token != '': if cwd == '/': cwd += token else: cwd = cwd + '/' + token return cwd def split_path(self, path): # instead of path.rpartition('/') tail = path.split('/')[-1] head = path[:-(len(tail) + 1)] return ('/' if head == '' else head, tail) # compare fname against pattern. Pattern may contain # the wildcards ? and *. def fncmp(self, fname, pattern): pi = 0 si = 0 while pi < len(pattern) and si < len(fname): if (fname[si] == pattern[pi]) or (pattern[pi] == '?'): si += 1 pi += 1 else: if pattern[pi] == '*': # recurse if pi == len(pattern.rstrip("*?")): # only wildcards left return True while si < len(fname): if self.fncmp(fname[si:], pattern[pi + 1:]): return True else: si += 1 return False else: return False if pi == len(pattern.rstrip("*")) and si == len(fname): return True else: return False def open_dataclient(self): if self.active: # active mode data_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) data_client.settimeout(_DATA_TIMEOUT) data_client.connect((self.act_data_addr, self.DATA_PORT)) log_msg(1, "FTP Data connection with:", self.act_data_addr) else: # passive mode data_client, data_addr = datasocket.accept() log_msg(1, "FTP Data connection with:", data_addr[0]) return data_client def mount(self): try: self.sd = SDCard(slot=3) uos.mount(self.sd,"/sd") return True except: return False def umount(self): try: uos.umount("/sd") try: self.sd.deinit() del self.sd except: pass # let all SD pins be inputs for i in bytearray([2,4,12,13,14,15]): p = Pin(i,Pin.IN) a = p.value() del p, a return True except: return False def exec_ftp_command(self, cl): global datasocket global client_busy global my_ip_addr try: collect() data = cl.readline().decode("utf-8").rstrip("\r\n") if len(data) <= 0: # No data, close # This part is NOT CLEAN; there is still a chance that a # closing data connection will be signalled as closing # command connection log_msg(1, "*** No data, assume QUIT") close_client(cl) return if client_busy: # check if another client is busy cl.sendall("400 Device busy.\r\n") # tell so the remote client return # and quit client_busy = True # now it's my turn # check for log-in state may done here, like # if self.logged_in == False and not command in\ # ("USER", "PASS", "QUIT"): # cl.sendall("530 Not logged in.\r\n") # return command = data.split()[0].upper() payload = data[len(command):].lstrip() # partition is missing path = self.get_absolute_path(self.cwd, payload) log_msg(1, "Command={}, Payload={}".format(command, payload)) if command == "USER": # self.logged_in = True cl.sendall("230 Logged in.\r\n") # If you want to see a password,return # "331 Need password.\r\n" instead # If you want to reject an user, return # "530 Not logged in.\r\n" elif command == "PASS": # you may check here for a valid password and return # "530 Not logged in.\r\n" in case it's wrong # self.logged_in = True cl.sendall("230 Logged in.\r\n") elif command == "SYST": cl.sendall("215 UNIX Type: L8\r\n") elif command in ("TYPE", "NOOP", "ABOR"): # just accept & ignore cl.sendall('200 OK\r\n') elif command == "QUIT": cl.sendall('221 Bye.\r\n') close_client(cl) elif command == "PWD" or command == "XPWD": cl.sendall('257 "{}"\r\n'.format(self.cwd)) elif command == "CWD" or command == "XCWD": try: if (uos.stat(path)[0] & 0o170000) == 0o040000: self.cwd = path cl.sendall('250 OK\r\n') else: cl.sendall('550 Fail\r\n') except: cl.sendall('550 Fail\r\n') elif command == "PASV": cl.sendall('227 Entering Passive Mode ({},{},{}).\r\n'.format( self.pasv_data_addr.replace('.', ','), _DATA_PORT >> 8, _DATA_PORT % 256)) self.active = False elif command == "PORT": items = payload.split(",") if len(items) >= 6: self.act_data_addr = '.'.join(items[:4]) if self.act_data_addr == "127.0.1.1": # replace by command session addr self.act_data_addr = self.remote_addr self.DATA_PORT = int(items[4]) * 256 + int(items[5]) cl.sendall('200 OK\r\n') self.active = True else: cl.sendall('504 Fail\r\n') elif command == "LIST" or command == "NLST": if payload.startswith("-"): option = payload.split()[0].lower() path = self.get_absolute_path( self.cwd, payload[len(option):].lstrip()) else: option = "" try: data_client = self.open_dataclient() cl.sendall("150 Directory listing:\r\n") self.send_list_data(path, data_client, command == "LIST" or 'l' in option) cl.sendall("226 Done.\r\n") data_client.close() except: cl.sendall('550 Fail\r\n') if data_client is not None: data_client.close() elif command == "RETR": try: data_client = self.open_dataclient() cl.sendall("150 Opened data connection.\r\n") self.send_file_data(path, data_client) # if the next statement is reached, # the data_client was closed. data_client = None cl.sendall("226 Done.\r\n") except: cl.sendall('550 Fail\r\n') if data_client is not None: data_client.close() elif command == "STOR" or command == "APPE": result = False try: data_client = self.open_dataclient() cl.sendall("150 Opened data connection.\r\n") if path == "/fpga": import ecp5 ecp5.prog_stream(data_client,_CHUNK_SIZE) result = ecp5.prog_close() data_client.close() elif path.startswith("/flash@"): import ecp5 dummy, addr = path.split("@") addr = int(addr) result = ecp5.flash_stream(data_client,addr) ecp5.flash_close() del addr, dummy data_client.close() elif path.startswith("/sd@"): import sdraw dummy, addr = path.split("@") addr = int(addr) sd_raw = sdraw.sdraw() result = sd_raw.sd_write_stream(data_client,addr) del sd_raw, addr, dummy data_client.close() else: self.save_file_data(path, data_client, "w" if command == "STOR" else "a") result = True # if the next statement is reached, # the data_client was closed. data_client = None except: if data_client is not None: data_client.close() if result: cl.sendall("226 Done.\r\n") else: cl.sendall('550 Fail\r\n') del result elif command == "SIZE": try: cl.sendall('213 {}\r\n'.format(uos.stat(path)[6])) except: cl.sendall('550 Fail\r\n') elif command == "STAT": if payload == "": cl.sendall("211-Connected to ({})\r\n" " Data address ({})\r\n" " TYPE: Binary STRU: File MODE: Stream\r\n" " Session timeout {}\r\n" "211 Client count is {}\r\n".format( self.remote_addr, self.pasv_data_addr, _COMMAND_TIMEOUT, len(client_list))) else: cl.sendall("213-Directory listing:\r\n") self.send_list_data(path, cl, True) cl.sendall("213 Done.\r\n") elif command == "DELE": try: uos.remove(path) cl.sendall('250 OK\r\n') except: cl.sendall('550 Fail\r\n') elif command == "RNFR": try: # just test if the name exists, exception if not uos.stat(path) self.fromname = path cl.sendall("350 Rename from\r\n") except: cl.sendall('550 Fail\r\n') elif command == "RNTO": try: uos.rename(self.fromname, path) cl.sendall('250 OK\r\n') except: cl.sendall('550 Fail\r\n') self.fromname = None elif command == "CDUP" or command == "XCUP": self.cwd = self.get_absolute_path(self.cwd, "..") cl.sendall('250 OK\r\n') elif command == "RMD" or command == "XRMD": try: uos.rmdir(path) cl.sendall('250 OK\r\n') except: cl.sendall('550 Fail\r\n') elif command == "MKD" or command == "XMKD": try: uos.mkdir(path) cl.sendall('250 OK\r\n') except: cl.sendall('550 Fail\r\n') elif command == "SITE": if path == "/mount": if self.mount(): cl.sendall('250 OK\r\n') else: cl.sendall('550 Fail\r\n') elif path == "/umount": if self.umount(): cl.sendall('250 OK\r\n') else: cl.sendall('550 Fail\r\n') elif path == "/passthru": import ecp5 ecp5.passthru() cl.sendall('250 OK passthru\r\n') elif path.endswith(".bit") or path.endswith(".bit.gz"): try: import ecp5 if ecp5.prog(path, close=False): if path.startswith("/sd/"): try: self.umount() cl.sendall('111 umount /sd OK\r\n') except: cl.sendall('411 umount /sd Fail\r\n') if ecp5.prog_close(): cl.sendall('250 OK\r\n') else: cl.sendall('550 Fail\r\n') else: cl.sendall('550 Fail\r\n') except: cl.sendall('550 Fail\r\n') else: if path.startswith("/"): exe=path[1:] else: exe=path try: exec(exe) cl.sendall('250 OK '+exe+'\r\n') except: cl.sendall('550 Fail '+exe+'\r\n') del exe else: cl.sendall("502 Unsupported command.\r\n") # log_msg(2, # "Unsupported command {} with payload {}".format(command, # payload)) # handle unexpected errors except Exception as err: log_msg(1, "Exception in exec_ftp_command: {}".format(err)) # tidy up before leaving client_busy = False
# allocate sample arrays # memoryview used to reduce heap allocation in while loop wav_samples = bytearray(1024) wav_samples_mv = memoryview(wav_samples) print('Starting') # continuously read audio samples from the WAV file # and write them to an I2S DAC while True: try: num_read = wav.readinto(wav_samples_mv) num_written = 0 # end of WAV file? if num_read == 0: # advance to first byte of Data section pos = wav.seek(44) else: # loop until all samples are written to the I2S peripheral while num_written < num_read: num_written += audio_out.write( wav_samples_mv[num_written:num_read], timeout=0) except (KeyboardInterrupt, Exception) as e: print('caught exception {} {}'.format(type(e).__name__, e)) break wav.close() uos.umount("/sd") sd.deinit() audio_out.deinit() print('Done')
class CardManager: """ High level auto-mounting SD Card manager """ def __init__(self, directory="/sd"): self._card = None self._directory = directory if Helpers.exists(self._directory) and \ not Helpers.is_dir(self._directory): raise Exception("Cannot mount {}".format(self._directory)) if not Helpers.exists(self._directory): uos.mkdir(self._directory) # Setup and IRQ on the CD line to auto-mount/dismount the sdcard pin = Pin(PIN_CD, Pin.IN, Pin.PULL_UP) pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._card_state_change) # These are for debouncing the card detect signal self._debounce_timer = None self._debounce = False self._card_state_change(pin) def is_card_present(self): return bool(self._card is not None) def _remove_debounce(self, test): self._debounce = False def _init_card(self): try: if self._card is None: self._card = SDCard(slot=SLOT, mosi=PIN_MOSI, miso=PIN_MISO, sck=PIN_SCK, cs=PIN_CS) except Exception: raise Exception("Card reader not present") return self._card def _deinit_card(self): self._card.deinit() self._card = None def _card_state_change(self, pin): """ Need to debounce this :param pin: :return: """ if self._debounce: return self._debounce = True self._debounce_timer = Timer(-1) self._debounce_timer.init(period=DEBOUNCE_TIME, mode=Timer.ONE_SHOT, callback=self._remove_debounce) irq_state = disable_irq() if pin.value(): # No card present if self._card: # Card may not be present on boot enable_irq(irq_state) uos.umount(self._directory) irq_state = disable_irq() self._deinit_card() else: try: card = self._init_card() enable_irq(irq_state) uos.mount(card, self._directory) irq_state = disable_irq() except OSError: # Mount issue, probably EPERM pass enable_irq(irq_state)
continue # keine '.py' datei, nächste datei in liste nehemen a = open(file, 'r') # file open in quelle read A if TTGO: b = open('/sd/' + file, 'w') # file open in zieldir write B else: b = open('subdir/' + file, 'w') # file open in zieldir write B kopf = "# ************ {} ****************\n".format(file) b.write(kopf) # titel # for zeilen in A while True: # read zeile n in A y = a.readline() # achtung : geht nur bei ASCII, zb. "xxx.py" if y == '': # nichts mehr gelesen ? break print(y, end='') # zeigen wie gelesen b.write(y) # write zeile nach B pass # next zeile # eine datei fertig # close A,B a.close() b.close() pass # nächste datei # unmount sd karte if TTGO: os.umount('/sd') filesystem.deinit() del filesystem
class sdraw: #def __init__(self): #print("SD RAW writer") #self.init_pinout_sd() def stopwatch_start(self): self.stopwatch_ms = ticks_ms() def stopwatch_stop(self, bytes_uploaded): elapsed_ms = ticks_ms() - self.stopwatch_ms transfer_rate_MBps = 0 if elapsed_ms > 0: transfer_rate_kBps = bytes_uploaded // elapsed_ms print("%d bytes uploaded in %d ms (%d kB/s)" % (bytes_uploaded, elapsed_ms, transfer_rate_kBps)) def open_file(self, filename, gz=False): filedata = open(filename, "rb") if gz: import uzlib return uzlib.DecompIO(filedata, 31) return filedata def open_web(self, url, gz=False): import socket _, _, host, path = url.split('/', 3) port = 80 if (len(host.split(':')) == 2): host, port = host.split(':', 2) print("host = ", host, " port = ", port, " path = ", path) addr = socket.getaddrinfo(host, port)[0][-1] s = socket.socket() s.connect(addr) s.send( bytes( 'GET /%s HTTP/1.0\r\nHost: %s\r\nAccept: image/*\r\n\r\n' % (path, host), 'utf8')) for i in range(100): # read first 100 lines searching for if len(s.readline()) < 3: # first empty line (contains "\r\n") break if gz: import uzlib return uzlib.DecompIO(s, 31) return s def sd_open(self): self.sd = SDCard(slot=3) def sd_close(self): self.sd.deinit() for i in bytearray([2, 4, 12, 13, 14, 15]): p = Pin(i, Pin.IN) a = p.value() del p, a del self.sd def sd_check_param(self, addr): if addr & 0x1FF: print("parameter must be rounded to block_size = 512 bytes") return False return True # negative addr means reference from end of the card def sd_wrapaddr(self, addr): if addr >= 0: return addr cardsize = self.sd.ioctl(4, 0) * 0x200 return cardsize + addr def sd_read(self, data, addr=0): if not self.sd_check_param(addr) or not self.sd_check_param(len(data)): return False self.sd_open() self.sd.readblocks(self.sd_wrapaddr(addr) // 0x200, data) self.sd_close() return True def sd_write_stream(self, filedata, addr=0, blocksize=16384): if not self.sd_check_param(addr): return False bytes_uploaded = 0 self.sd_open() addr = self.sd_wrapaddr(addr) nearend = self.sd_wrapaddr(-blocksize) self.stopwatch_start() block = bytearray(blocksize) while True: waddr = addr + bytes_uploaded if waddr >= nearend and len(block) > 0x200: block = bytearray(0x200) if filedata.readinto(block): self.sd.writeblocks(waddr // 0x200, block) bytes_uploaded += len(block) else: break self.stopwatch_stop(bytes_uploaded) self.sd_close() return True