From 8ac257b97aea06441fdd71cffce17c9bab6fbb2e Mon Sep 17 00:00:00 2001 From: Joerg Deckert Date: Tue, 10 Dec 2013 16:11:08 +0100 Subject: [PATCH] first version with network support (not working) --- lib/adm-lan.spin | 173 ++++ lib/api_telnet_serial.spin | 1 + lib/driver_enc28j60.spin | 1 + lib/driver_socket.spin | 1 + lib/glob-con.spin | 7 + lib/reg-ios.spin | 14 + system/administra/admnet/admnet.spin | 1141 ++++++++++++++++++++++++++ system/regnatix/ipconfig.spin | 173 ++++ 8 files changed, 1511 insertions(+) create mode 100644 lib/adm-lan.spin create mode 100644 lib/api_telnet_serial.spin create mode 100644 lib/driver_enc28j60.spin create mode 100644 lib/driver_socket.spin create mode 100644 system/administra/admnet/admnet.spin create mode 100644 system/regnatix/ipconfig.spin diff --git a/lib/adm-lan.spin b/lib/adm-lan.spin new file mode 100644 index 0000000..ffdb5c3 --- /dev/null +++ b/lib/adm-lan.spin @@ -0,0 +1,173 @@ +{{ LAN-Funktionen für Administra }} + +CON 'Signaldefinitionen -------------------------------------------------------------------------- + +'signaldefinitionen administra (todo: nach glob-con.spin auslagern!!!) + +#14, A_NETCS,A_NETSCK,A_NETSI,A_NETSO 'Pins zum ENC28J60 + +CON 'NVRAM Konstanten -------------------------------------------------------------------------- + +' todo: nach glob-con.spin auslagern!!! + +#4, NVRAM_IPADDR +#8, NVRAM_IPMASK +#12, NVRAM_IPGW +#16, NVRAM_IPDNS +#20, NVRAM_IPBOOT +#24, NVRAM_HIVE ' 4 Bytes + +CON + + ' buffer sizes, must be a power of 2 + rxlen = 2048 + txlen = 128 + +VAR + + byte ftp_bufrx1[rxlen] ' buffers for connection to server + byte ftp_buftx1[txlen] + + byte ftp_bufrx2[rxlen] ' buffers for connection from server + byte ftp_buftx2[txlen] + + byte strTemp[128] + +OBJ + + gc : "glob-con" 'globale konstanten + num : "glob-numbers" 'Number Engine + rtc : "adm-rtc" 'RTC-Engine + com : "adm-com" 'serielle schnittstelle (nur zum Debugging genutzt) + sock : "api_telnet_serial" 'TCP Socket Funktionen + +PUB start | hiveid, hivestr, strpos, macpos + + ip_addr := rtc.getNVSRAM(NVRAM_IPADDR) + ip_addr[1] := rtc.getNVSRAM(NVRAM_IPADDR+1) + ip_addr[2] := rtc.getNVSRAM(NVRAM_IPADDR+2) + ip_addr[3] := rtc.getNVSRAM(NVRAM_IPADDR+3) + + ip_subnet := rtc.getNVSRAM(NVRAM_IPMASK) + ip_subnet[1] := rtc.getNVSRAM(NVRAM_IPMASK+1) + ip_subnet[2] := rtc.getNVSRAM(NVRAM_IPMASK+2) + ip_subnet[3] := rtc.getNVSRAM(NVRAM_IPMASK+3) + + ip_gateway := rtc.getNVSRAM(NVRAM_IPGW) + ip_gateway[1] := rtc.getNVSRAM(NVRAM_IPGW+1) + ip_gateway[2] := rtc.getNVSRAM(NVRAM_IPGW+2) + ip_gateway[3] := rtc.getNVSRAM(NVRAM_IPGW+3) + + ip_dns := rtc.getNVSRAM(NVRAM_IPDNS) + ip_dns[1] := rtc.getNVSRAM(NVRAM_IPDNS+1) + ip_dns[2] := rtc.getNVSRAM(NVRAM_IPDNS+2) + ip_dns[3] := rtc.getNVSRAM(NVRAM_IPDNS+3) + + hiveid := rtc.getNVSRAM(NVRAM_HIVE) + hiveid := hiveid + rtc.getNVSRAM(NVRAM_HIVE+1) << 8 + hiveid := hiveid + rtc.getNVSRAM(NVRAM_HIVE+2) << 16 + hiveid := hiveid + rtc.getNVSRAM(NVRAM_HIVE+3) << 24 + hivestr := num.ToStr(hiveid, num#DEC) + strpos := strsize(hivestr) + macpos := 5 + repeat while (strpos AND macpos) + strpos-- + if(strpos) + strpos-- + mac_addr[macpos] := num.FromStr(hivestr+strpos, num#HEX) + byte[hivestr+strpos] := 0 + macpos-- + + sock.start(A_NETCS,A_NETSCK,A_NETSI,A_NETSO, -1, @mac_addr, @ip_addr) + +PUB stop + + sock.stop + +PUB ftpOpen(addr) : connected 'FTP-Verbindung öffnen + + com.str(string("ftpOpen Start",13,10)) + repeat 5 'mehrmals probieren, falls z.B. TCP-Engine-Cog noch nicht bereit + sock.connect(addr, 21, @ftp_bufrx1, rxlen, @ftp_buftx1, txlen) + 'sock.resetBuffers + if connected := sock.waitConnectTimeout(1500) + 'todo: einfügen? if getResponse(string("220")) + if getResponse(string("220 ")) + com.str(string("Send: USER anonymous",13,10)) + sock.str(string("USER anonymous",13,10)) + if getResponse(string("230 ")) + quit + else + sock.close + +PUB ftpClose 'FTP-Verbindung schließen + + com.str(string("Send: QUIT",13,10)) + sock.str(string("QUIT",13,10)) + getResponse(string("221 ")) + sock.close + +PUB ftpOpenData(addr,port) : connected + +PUB ftpCloseData + +PUB ftpBoot 'zum Boot-Server verbinden + + ip_boot := rtc.getNVSRAM(NVRAM_IPBOOT) << 24 + ip_boot := ip_boot + rtc.getNVSRAM(NVRAM_IPBOOT+1) << 16 + ip_boot := ip_boot + rtc.getNVSRAM(NVRAM_IPBOOT+2) << 8 + ip_boot := ip_boot + rtc.getNVSRAM(NVRAM_IPBOOT+3) + + if ip_boot + if ftpOpen(ip_boot) + ftpClose + +PUB ftpListName 'Verzeichniseintrag lesen + + return + +PRI getResponse (strOk) : respOk | len + + respOk := FALSE + + repeat + readLine + com.str(@strTemp) + com.str(string(13,10)) + if strsize(@strTemp) == 0 + quit + 'byte[@strTemp+strsize(strOk)] := 0 + strTemp[strsize(strOk)] := 0 + com.str(string("StrOk: ")) + com.str(strOk) + com.str(string("StrComp: ")) + com.str(@strTemp) + com.str(string(13,10)) + if strcomp(@strTemp, strOk) + respOk := TRUE + + return respOk + +PRI readLine | i, ch + + repeat i from 0 to 126 + ch := sock.rxtime(500) + if ch == 13 + ch := sock.rxtime(500) + if ch == -1 or ch == 10 + quit + strTemp[i] := ch + + strTemp[i] := 0 + + return i + +DAT + long ' long alignment for addresses + ip_addr byte 10, 1, 1, 1 'ip + ip_subnet byte 255, 255, 255, 0 'subnet-maske + ip_gateway byte 10, 1, 1, 254 'gateway + ip_dns byte 10, 1, 1, 254 'dns + ip_boot long 0 'boot-server (IP address in long) + mac_addr byte $c0, $de, $ba, $be, $00, $00 'mac-adresse + diff --git a/lib/api_telnet_serial.spin b/lib/api_telnet_serial.spin new file mode 100644 index 0000000..69a22ed --- /dev/null +++ b/lib/api_telnet_serial.spin @@ -0,0 +1 @@ +{{ PropTCP Sockets - FullDuplexSerial API Layer -------------------------------------------- Copyright (c) 2006-2009 Harrison Pham Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The latest version of this software can be obtained from http://hdpham.com/PropTCP and http://obex.parallax.com/}}'' NOTICE: All buffer sizes must be a power of 2!OBJ tcp : "driver_socket" VAR long handle word listenport byte listening long ptrrxbuff, ptrtxbuff word rxlen, txlenPUB start(cs, sck, si, so, xtalout, macptr, ipconfigptr) tcp.start(cs, sck, si, so, xtalout, macptr, ipconfigptr)PUB stop tcp.stopPUB connect(ipaddr, remoteport, _ptrrxbuff, _rxlen, _ptrtxbuff, _txlen) {if tcp.isValidHandle(handle) close} listening := false handle := -1 handle := tcp.connect(ipaddr, remoteport, _ptrrxbuff, _rxlen, _ptrtxbuff, _txlen) return handle PUB listen(port, _ptrrxbuff, _rxlen, _ptrtxbuff, _txlen) {if tcp.isValidHandle(handle) close} listenport := port ptrrxbuff := _ptrrxbuff rxlen := _rxlen ptrtxbuff := _ptrtxbuff txlen := _txlen listening := true handle := -1 handle := tcp.listen(listenport, ptrrxbuff, rxlen, ptrtxbuff, txlen) return handlePUB relisten if listening ifnot tcp.isValidHandle(handle) listen(listenport, ptrrxbuff, rxlen, ptrtxbuff, txlen)PUB isConnected return tcp.isConnected(handle)PUB rxcount return tcp.getReceiveBufferCount(handle)PUB resetBuffers tcp.resetBuffers(handle)PUB waitConnectTimeout(ms) : connected | t t := cnt repeat until (connected := isConnected) or (((cnt - t) / (clkfreq / 1000)) > ms)PUB close tcp.close(handle) handle := -1PUB rxflush repeat while rxcheck => 0PUB rxcheck : rxbyte {if listening relisten rxbyte := tcp.readByteNonBlocking(handle) else} rxbyte := tcp.readByteNonBlocking(handle) if (not tcp.isConnected(handle)) and (rxbyte == -1) abort tcp#ERRSOCKETCLOSEDPUB rxtime(ms) : rxbyte | t t := cnt repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > msPUB rx : rxbyte repeat while (rxbyte := rxcheck) < 0PUB rxdatatime(ptr, maxlen, ms) : len | t t := cnt repeat until (len := tcp.readDataNonBlocking(handle, ptr, maxlen)) => 0 or (cnt - t) / (clkfreq / 1000) > msPUB rxdata(ptr, maxlen) return tcp.readData(handle, ptr, maxlen)PUB txflush tcp.flush(handle)PUB txcheck(txbyte) {if listening relisten} ifnot tcp.isConnected(handle) abort tcp#ERRSOCKETCLOSED return tcp.writeByteNonBlocking(handle, txbyte)PUB tx(txbyte) repeat while txcheck(txbyte) < 0PUB txdata(ptr, len) {if listening relisten} tcp.writeData(handle, ptr, len)PUB str(stringptr) txdata(stringptr, strsize(stringptr)) PUB dec(value) | i'' Print a decimal number if value < 0 -value tx("-") i := 1_000_000_000 repeat 10 if value => i tx(value / i + "0") value //= i result~~ elseif result or i == 1 tx("0") i /= 10PUB hex(value, digits)'' Print a hexadecimal number value <<= (8 - digits) << 2 repeat digits tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))PUB bin(value, digits)'' Print a binary number value <<= 32 - digits repeat digits tx((value <-= 1) & 1 + "0") \ No newline at end of file diff --git a/lib/driver_enc28j60.spin b/lib/driver_enc28j60.spin new file mode 100644 index 0000000..67a1724 --- /dev/null +++ b/lib/driver_enc28j60.spin @@ -0,0 +1 @@ +{{ ENC28J60 Ethernet MAC / PHY Driver ---------------------------------- Copyright (c) 2006-2009 Harrison Pham Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The latest version of this software can be obtained from http://hdpham.com/PropTCP and http://obex.parallax.com/ Constant Names / Code Logic based on code from Microchip Technology, Inc.'s enc28j60.c / enc28j60.h source files}}CON version = 6 ' major version release = 0 ' minor versionCON' ***************************************' ** ENC28J60 SRAM Defines **' *************************************** ' ENC28J60 Frequency enc_freq = 25_000_000 ' ENC28J60 SRAM Usage Constants MAXFRAME = 1518 ' 6 (src addr) + 6 (dst addr) + 2 (type) + 1500 (data) + 4 (FCS CRC) = 1518 bytes TX_BUFFER_SIZE = 1518 TXSTART = 8192 - (TX_BUFFER_SIZE + 8) TXEND = TXSTART + (TX_BUFFER_SIZE + 8) RXSTART = $0000 RXSTOP = (TXSTART - 2) | $0001 ' must be odd (B5 Errata) RXSIZE = (RXSTOP - RXSTART + 1)DAT' ***************************************' ** MAC Address Vars / Defaults **' *************************************** ' ** This is the default MAC address used by this driver. The parent object ' can override this by passing a pointer to a new MAC address in the public ' start() method. It is recommend that this is done to provide a level of ' abstraction and makes tcp stack design easier. ' ** This is the ethernet MAC address, it is critical that you change this ' if you have more than one device using this code on a local network. ' ** If you plan on commercial deployment, you must purchase MAC address ' groups from IEEE or some other standards organization. eth_mac byte $02, $00, $00, $00, $00, $01' ***************************************' ** Global Variables **' *************************************** rxlen word 0 tx_end word 0 packetheader byte 0[6] 'packet byte 0[MAXFRAME]PUB start(_cs, _sck, _si, _so, xtalout, macptr)'' Starts the driver (uses 1 cog for spi engine) ' Since some people don't have 25mhz crystals, we use the cog counters ' to generate a 25mhz frequency for the ENC28J60 (I love the Propeller) ' Note: This requires a main crystal that is a multiple of 25mhz (5mhz works). spi_start(_cs, _sck, _so, _si, xtalout) ' If a MAC address pointer is provided (addr > -1) then copy it into ' the MAC address array (this kind of wastes space, but simplifies usage). if macptr > -1 bytemove(@eth_mac, macptr, 6) delay_ms(50) init_ENC28J60 ' return the chip silicon version banksel(EREVID) return rd_cntlreg(EREVID)PUB stop'' Stops the driver, frees 1 cog spi_stopPUB rd_macreg(address) : data'' Read MAC Control Register spi_out_cs(cRCR | address) spi_out_cs(0) ' transmit dummy byte data := spi_in ' get actual dataPUB rd_cntlreg(address) : data'' Read ETH Control Register spi_out_cs(cRCR | address) data := spi_inPUB wr_reg(address, data)'' Write MAC and ETH Control Register spi_out_cs(cWCR | address) spi_out(data)PUB bfc_reg(address, data)'' Clear Control Register Bits spi_out_cs(cBFC | address) spi_out(data)PUB bfs_reg(address, data)'' Set Control Register Bits spi_out_cs(cBFS | address) spi_out(data)PUB soft_reset'' Soft Reset ENC28J60 spi_out(cSC)PUB banksel(register)'' Select Control Register Bank bfc_reg(ECON1, %0000_0011) bfs_reg(ECON1, register >> 8) ' high bytePUB rd_phy(register) | low, high'' Read ENC28J60 PHY Register banksel(MIREGADR) wr_reg(MIREGADR, register) wr_reg(MICMD, MICMD_MIIRD) banksel(MISTAT) repeat while ((rd_macreg(MISTAT) & MISTAT_BUSY) > 0) banksel(MIREGADR) wr_reg(MICMD, $00) low := rd_macreg(MIRDL) high := rd_macreg(MIRDH) return (high << 8) + lowPUB wr_phy(register, data)'' Write ENC28J60 PHY Register banksel(MIREGADR) wr_reg(MIREGADR, register) wr_reg(MIWRL, data) wr_reg(MIWRH, data >> 8) banksel(MISTAT) repeat while ((rd_macreg(MISTAT) & MISTAT_BUSY) > 0)PUB rd_sram : data'' Read ENC28J60 8k Buffer Memory spi_out_cs(cRBM) data := spi_inPUB wr_sram(data)'' Write ENC28J60 8k Buffer Memory spi_out_cs(cWBM) spi_out(data)PUB init_ENC28J60 | i'' Init ENC28J60 Chip repeat i := rd_cntlreg(ESTAT) while (i & $08) OR (!i & ESTAT_CLKRDY) soft_reset delay_ms(5) ' reset delay bfc_reg(ECON1, ECON1_RXEN) ' stop send / recv bfc_reg(ECON1, ECON1_TXRTS) bfs_reg(ECON2, ECON2_AUTOINC) ' enable auto increment of sram pointers (already default) packetheader[nextpacket_low] := RXSTART packetheader[nextpacket_high] := constant(RXSTART >> 8) banksel(ERDPTL) wr_reg(ERDPTL, RXSTART) wr_reg(ERDPTH, constant(RXSTART >> 8)) banksel(ERXSTL) wr_reg(ERXSTL, RXSTART) wr_reg(ERXSTH, constant(RXSTART >> 8)) wr_reg(ERXRDPTL, RXSTOP) wr_reg(ERXRDPTH, constant(RXSTOP >> 8)) wr_reg(ERXNDL, RXSTOP) wr_reg(ERXNDH, constant(RXSTOP >> 8)) wr_reg(ETXSTL, TXSTART) wr_reg(ETXSTH, constant(TXSTART >> 8)) banksel(MACON1) wr_reg(MACON1, constant(MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN)) wr_reg(MACON3, constant(MACON3_TXCRCEN | MACON3_PADCFG0 | MACON3_FRMLNEN)) ' don't timeout transmissions on saturated media wr_reg(MACON4, MACON4_DEFER) ' collisions occur at 63rd byte wr_reg(MACLCON2, 63) wr_reg(MAIPGL, $12) wr_reg(MAIPGH, $0C) wr_reg(MAMXFLL, MAXFRAME) wr_reg(MAMXFLH, constant(MAXFRAME >> 8)) ' back-to-back inter-packet gap time ' full duplex = 0x15 (9.6us) ' half duplex = 0x12 (9.6us) wr_reg(MABBIPG, $12) wr_reg(MAIPGL, $12) wr_reg(MAIPGH, $0C) ' write mac address to the chip banksel(MAADR1) wr_reg(MAADR1, eth_mac[0]) wr_reg(MAADR2, eth_mac[1]) wr_reg(MAADR3, eth_mac[2]) wr_reg(MAADR4, eth_mac[3]) wr_reg(MAADR5, eth_mac[4]) wr_reg(MAADR6, eth_mac[5]) ' half duplex wr_phy(PHCON2, PHCON2_HDLDIS) wr_phy(PHCON1, $0000) ' set LED options wr_phy(PHLCON, $0742) ' $0472 => ledA = link, ledB = tx/rx ' $0742 => ledA = tx/rx, ledB = link ' enable packet reception bfs_reg(ECON1, ECON1_RXEN)PUB get_frame(pktptr) | packet_addr, new_rdptr'' Get Ethernet Frame from Buffer banksel(ERDPTL) wr_reg(ERDPTL, packetheader[nextpacket_low]) wr_reg(ERDPTH, packetheader[nextpacket_high]) repeat packet_addr from 0 to 5 packetheader[packet_addr] := rd_sram rxlen := (packetheader[rec_bytecnt_high] << 8) + packetheader[rec_bytecnt_low] 'bytefill(@packet, 0, MAXFRAME) ' Uncomment this if you want to clean out the buffer first ' otherwise, leave commented since it's faster to just leave stuff ' in the buffer ' protect from oversized packet if rxlen =< MAXFRAME rd_block(pktptr, rxlen) {repeat packet_addr from 0 to rxlen - 1 BYTE[@packet][packet_addr] := rd_sram} new_rdptr := (packetheader[nextpacket_high] << 8) + packetheader[nextpacket_low] ' handle errata read pointer start (must be odd) --new_rdptr if (new_rdptr < RXSTART) OR (new_rdptr > RXSTOP) new_rdptr := RXSTOP bfs_reg(ECON2, ECON2_PKTDEC) banksel(ERXRDPTL) wr_reg(ERXRDPTL, new_rdptr) wr_reg(ERXRDPTH, new_rdptr >> 8)PUB start_frame'' Start frame - Inits the NIC and sets stuff banksel(EWRPTL) wr_reg(EWRPTL, TXSTART) wr_reg(EWRPTH, constant(TXSTART >> 8)) tx_end := constant(TXSTART - 1) ' start location is really address 0, so we are sending a count of - 1 wr_frame(cTXCONTROL)PUB wr_frame(data)'' Write frame data wr_sram(data) ++tx_endPUB wr_block(startaddr, count) blockwrite(startaddr, count) tx_end += countPUB rd_block(startaddr, count) blockread(startaddr, count)PUB send_frame'' Sends frame'' Will retry on send failure up to 15 times with a 1ms delay in between repeats repeat 15 if p_send_frame ' send packet, if successful then quit retry loop quit delay_ms(1)PRI p_send_frame | i, eirval' Sends the frame banksel(ETXSTL) wr_reg(ETXSTL, TXSTART) wr_reg(ETXSTH, constant(TXSTART >> 8)) banksel(ETXNDL) wr_reg(ETXNDL, tx_end) wr_reg(ETXNDH, tx_end >> 8) ' B5 Errata #10 - Reset transmit logic before send bfs_reg(ECON1, ECON1_TXRST) bfc_reg(ECON1, ECON1_TXRST) ' B5 Errata #10 & #13: Reset interrupt error flags bfc_reg(EIR, constant(EIR_TXERIF | EIR_TXIF)) ' trigger send bfs_reg(ECON1, ECON1_TXRTS) ' fix for transmit stalls (derived from errata B5 #13), watches TXIF and TXERIF bits ' also implements a ~3.75ms (15 * 250us) timeout if send fails (occurs on random packet collisions) ' btw: this took over 10 hours to fix due to the elusive undocumented bug i := 0 repeat eirval := rd_cntlreg(EIR) if ((eirval & constant(EIR_TXERIF | EIR_TXIF)) > 0) quit if (++i => 15) eirval := EIR_TXERIF quit delay_us(250) ' B5 Errata #13 - Reset TXRTS if failed send then reset logic bfc_reg(ECON1, ECON1_TXRTS) if ((eirval & EIR_TXERIF) == 0) return true ' successful send (no error interrupt) else return false ' failed send (error interrupt)PUB get_mac_pointer'' Gets mac address pointer return @eth_macPUB get_rxlen'' Gets received packet length return rxlen - 4 ' knock off the 4 byte Frame Check Sequence CRC, not used anywhere outside of this driver (pg 31 datasheet)PRI delay_us(Duration) waitcnt(((clkfreq / 1_000_000 * Duration - 3928)) + cnt) PRI delay_ms(Duration) waitcnt(((clkfreq / 1_000 * Duration - 3932)) + cnt)' ***************************************' ** ASM SPI Engine **' *************************************** DAT cog long 0 command long 0 CON SPIOUT = %0000_0001 SPIIN = %0000_0010 SRAMWRITE = %0000_0100 SRAMREAD = %0000_1000 CSON = %0001_0000 CSOFF = %0010_0000 CKSUM = %0100_0000 SPIBITS = 8PRI spi_out(value) setcommand(constant(SPIOUT | CSON | CSOFF), @value) PRI spi_out_cs(value) setcommand(constant(SPIOUT | CSON), @value)PRI spi_in : value setcommand(constant(SPIIN | CSON | CSOFF), @value) PRI spi_in_cs : value setcommand(constant(SPIIN | CSON), @value)PRI blockwrite(startaddr, count) setcommand(SRAMWRITE, @startaddr)PRI blockread(startaddr, count) setcommand(SRAMREAD, @startaddr)PUB chksum_add(startaddr, count) setcommand(CKSUM, @startaddr) return startaddr PRI spi_start(_cs, _sck, _di, _do, _freqpin) spi_stop cspin := |< _cs dipin := |< _di dopin := |< _do clkpin := |< _sck ctramode := %0_00100_00_0000_0000_0000_0000_0000_0000 + _sck ctrbmode := %0_00100_00_0000_0000_0000_0000_0000_0000 + _do spi_setupfreqsynth(_freqpin) cog := cognew(@init, @command) + 1 PRI spi_stop if cog cogstop(cog~ - 1) ctra := 0 command~ PRI setcommand(cmd, argptr) command := cmd << 16 + argptr 'write command and pointer repeat while command 'wait for command to be cleared, signifying receiptPRI spi_setupfreqsynth(pin) if pin < 0 ' pin num was negative -> disable freq synth return dira[pin] := 1 ctra := constant(%00010 << 26) '..set PLL mode ctra |= constant((>|((enc_freq - 1) / 1_000_000)) << 23) 'set PLLDIV frqa := spi_fraction(enc_freq, CLKFREQ, constant(4 - (>|((enc_freq - 1) / 1_000_000)))) 'Compute FRQA/FRQB value ctra |= pin 'set PINA to complete CTRA/CTRB valuePRI spi_fraction(a, b, shift) : f if shift > 0 'if shift, pre-shift a or b left a <<= shift 'to maintain significant bits while if shift < 0 'insuring proper result b <<= -shift repeat 32 'perform long division of a/b f <<= 1 if a => b a -= b f++ a <<= 1DAT orginit or dira, cspin 'pin directions andn dira, dipin or dira, dopin or dira, clkpin or outa, cspin 'turn off cs (bring it high) mov frqb, #0 'disable ctrb increment mov ctrb, ctrbmode loop wrlong zero,par 'zero command (tell spin we are done processing):subloop rdlong t1,par wz 'wait for command if_z jmp #:subloop mov addr, t1 'used for holding return addr to spin vars rdlong arg0, t1 'arg0 add t1, #4 rdlong arg1, t1 'arg1 mov lkup, addr 'get the command var from spin shr lkup, #16 'extract the cmd from the command var test lkup, #CSON wz 'turn on cs if_nz andn outa, cspin test lkup, #SPIOUT wz 'spi out if_nz call #spi_out_ test lkup, #SPIIN wz 'spi in if_nz call #xspi_in_ test lkup, #SRAMWRITE wz 'sram block write if_nz jmp #sram_write_ test lkup, #SRAMREAD wz 'sram block read if_nz jmp #sram_read_ test lkup, #CSOFF wz 'cs off if_nz or outa, cspin test lkup, #CKSUM wz 'perform checksum if_nz call #csum16 jmp #loop ' no cmd found spi_out_ andn outa, clkpin shl arg0, #24 mov phsb, arg0 ' data to write mov frqa, freqw ' 20MHz write frequency mov phsa, #0 ' start at clocking at 0 mov ctra, ctramode ' send data @ 20MHz rol phsb, #1 rol phsb, #1 rol phsb, #1 rol phsb, #1 rol phsb, #1 rol phsb, #1 rol phsb, #1 mov ctra, #0 ' disable andn outa, clkpin spi_out__ret retspi_in_ andn outa, clkpin mov phsa, phsr ' start phs for clock mov frqa, freqr ' 10MHz read frequency nop mov ctra, ctramode ' start clocking test dipin, ina wc rcl arg0, #1 test dipin, ina wc rcl arg0, #1 test dipin, ina wc rcl arg0, #1 test dipin, ina wc rcl arg0, #1 test dipin, ina wc rcl arg0, #1 test dipin, ina wc rcl arg0, #1 test dipin, ina wc rcl arg0, #1 test dipin, ina wc mov ctra, #0 ' stop clocking rcl arg0, #1 andn outa, clkpin spi_in__ret retxspi_in_ call #spi_in_ wrbyte arg0, addr ' write byte back to spin result varxspi_in__ret ret' SRAM Block Read/Writesram_write_ ' block write (arg0=hub addr, arg1=count) mov t1, arg0 mov t2, arg1 andn outa, cspin mov arg0, #cWBM call #spi_out_:loop rdbyte arg0, t1 call #spi_out_ add t1, #1 djnz t2, #:loop or outa, cspin jmp #loop sram_read_ ' block read (arg0=hub addr, arg1=count) mov t1, arg0 mov t2, arg1 andn outa, cspin mov arg0, #cRBM call #spi_out_:loop call #spi_in_ wrbyte arg0, t1 add t1, #1 djnz t2, #:loop or outa, cspin jmp #loopcsum16 ' performs checksum 16bit additions on the data ' arg0=hub addr, arg1=length, writes sum to first arg mov t1, #0 ' clear sum:loop rdbyte t2, arg0 ' read two bytes (16 bits) add arg0, #1 rdbyte t3, arg0 add arg0, #1 shl t2, #8 ' build the word add t2, t3 add t1, t2 ' add numbers mov t2, t1 ' add lower and upper words together shr t2, #16 and t1, hffff add t1, t2 sub arg1, #2 cmp arg1, #1 wz, wc if_nc_and_nz jmp #:loop if_z rdbyte t2, arg0 ' add last byte (odd) if_z shl t2, #8 if_z add t1, t2 wrlong t1, addr ' return result back to SPINcsum16_ret retzero long 0 'constants 'values filled by spin code before launchingcspin long 0 ' chip select pindipin long 0 ' data in pin (enc28j60 -> prop)dopin long 0 ' data out pin (prop -> enc28j60)clkpin long 0 ' clock pin (prop -> enc28j60)ctramode long 0 ' ctr mode for CLKctrbmode long 0 ' ctr mode for SPI Outhffff long $FFFFfreqr long $2000_0000 'frequency of SCK /8 for receivefreqw long $4000_0000 'frequency of SCK /4 for sendphsr long $6000_0000 'temp variablest1 res 1 ' loop and cog shutdown t2 res 1 ' loop and cog shutdownt3 res 1 ' Used to hold DataValue SHIFTIN/SHIFTOUTt4 res 1 ' Used to hold # of Bitst5 res 1 ' Used for temporary data maskaddr res 1 ' Used to hold return address of first Argument passedlkup res 1 ' Used to hold command lookup 'arguments passed to/from high-level Spinarg0 res 1 ' bits / start addressarg1 res 1 ' value / count CON' ***************************************' ** ENC28J60 Control Constants **' *************************************** ' ENC28J60 opcodes (OR with 5bit address) cWCR = %010 << 5 ' write control register command cBFS = %100 << 5 ' bit field set command cBFC = %101 << 5 ' bit field clear command cRCR = %000 << 5 ' read control register command cRBM = (%001 << 5) | $1A ' read buffer memory command cWBM = (%011 << 5) | $1A ' write buffer memory command cSC = (%111 << 5) | $1F ' system command ' This is used to trigger TX in the ENC28J60, it shouldn't change, but you never know... cTXCONTROL = $0E ' Packet header format (tail of the receive packet in the ENC28J60 SRAM) #0,nextpacket_low,nextpacket_high,rec_bytecnt_low,rec_bytecnt_high,rec_status_low,rec_status_high' ***************************************' ** ENC28J60 Register Defines **' *************************************** ' Bank 0 registers -------- ERDPTL = $00 ERDPTH = $01 EWRPTL = $02 EWRPTH = $03 ETXSTL = $04 ETXSTH = $05 ETXNDL = $06 ETXNDH = $07 ERXSTL = $08 ERXSTH = $09 ERXNDL = $0A ERXNDH = $0B ERXRDPTL = $0C ERXRDPTH = $0D ERXWRPTL = $0E ERXWRPTH = $0F EDMASTL = $10 EDMASTH = $11 EDMANDL = $12 EDMANDH = $13 EDMADSTL = $14 EDMADSTH = $15 EDMACSL = $16 EDMACSH = $17 ' = $18 ' = $19 ' r = $1A EIE = $1B EIR = $1C ESTAT = $1D ECON2 = $1E ECON1 = $1F ' Bank 1 registers ----- EHT0 = $100 EHT1 = $101 EHT2 = $102 EHT3 = $103 EHT4 = $104 EHT5 = $105 EHT6 = $106 EHT7 = $107 EPMM0 = $108 EPMM1 = $109 EPMM2 = $10A EPMM3 = $10B EPMM4 = $10C EPMM5 = $10D EPMM6 = $10E EPMM7 = $10F EPMCSL = $110 EPMCSH = $111 ' = $112 ' = $113 EPMOL = $114 EPMOH = $115 EWOLIE = $116 EWOLIR = $117 ERXFCON = $118 EPKTCNT = $119 ' r = $11A ' EIE = $11B ' EIR = $11C ' ESTAT = $11D ' ECON2 = $11E ' ECON1 = $11F ' Bank 2 registers ----- MACON1 = $200 MACON2 = $201 MACON3 = $202 MACON4 = $203 MABBIPG = $204 ' = $205 MAIPGL = $206 MAIPGH = $207 MACLCON1 = $208 MACLCON2 = $209 MAMXFLL = $20A MAMXFLH = $20B ' r = $20C MAPHSUP = $20D ' r = $20E ' = $20F ' r = $210 MICON = $211 MICMD = $212 ' = $213 MIREGADR = $214 ' r = $215 MIWRL = $216 MIWRH = $217 MIRDL = $218 MIRDH = $219 ' r = $21A ' EIE = $21B ' EIR = $21C ' ESTAT = $21D ' ECON2 = $21E ' ECON1 = $21F ' Bank 3 registers ----- MAADR5 = $300 MAADR6 = $301 MAADR3 = $302 MAADR4 = $303 MAADR1 = $304 MAADR2 = $305 {MAADR1 = $300 MAADR0 = $301 MAADR3 = $302 MAADR2 = $303 MAADR5 = $304 MAADR4 = $305} EBSTSD = $306 EBSTCON = $307 EBSTCSL = $308 EBSTCSH = $309 MISTAT = $30A ' = $30B ' = $30C ' = $30D ' = $30E ' = $30F ' = $310 ' = $311 EREVID = $312 ' = $313 ' = $314 ECOCON = $315 ' EPHTST $316 EFLOCON = $317 EPAUSL = $318 EPAUSH = $319 ' r = $31A ' EIE = $31B ' EIR = $31C ' ESTAT = $31D ' ECON2 = $31E ' ECON1 = $31F {****************************************************************************** * PH Register Locations ******************************************************************************} PHCON1 = $00 PHSTAT1 = $01 PHID1 = $02 PHID2 = $03 PHCON2 = $10 PHSTAT2 = $11 PHIE = $12 PHIR = $13 PHLCON = $14 {****************************************************************************** * Individual Register Bits ******************************************************************************} ' ETH/MAC/MII bits ' EIE bits ---------- EIE_INTIE = (1<<7) EIE_PKTIE = (1<<6) EIE_DMAIE = (1<<5) EIE_LINKIE = (1<<4) EIE_TXIE = (1<<3) EIE_WOLIE = (1<<2) EIE_TXERIE = (1<<1) EIE_RXERIE = (1) ' EIR bits ---------- EIR_PKTIF = (1<<6) EIR_DMAIF = (1<<5) EIR_LINKIF = (1<<4) EIR_TXIF = (1<<3) EIR_WOLIF = (1<<2) EIR_TXERIF = (1<<1) EIR_RXERIF = (1) ' ESTAT bits --------- ESTAT_INT = (1<<7) ESTAT_LATECOL = (1<<4) ESTAT_RXBUSY = (1<<2) ESTAT_TXABRT = (1<<1) ESTAT_CLKRDY = (1) ' ECON2 bits -------- ECON2_AUTOINC = (1<<7) ECON2_PKTDEC = (1<<6) ECON2_PWRSV = (1<<5) ECON2_VRTP = (1<<4) ECON2_VRPS = (1<<3) ' ECON1 bits -------- ECON1_TXRST = (1<<7) ECON1_RXRST = (1<<6) ECON1_DMAST = (1<<5) ECON1_CSUMEN = (1<<4) ECON1_TXRTS = (1<<3) ECON1_RXEN = (1<<2) ECON1_BSEL1 = (1<<1) ECON1_BSEL0 = (1) ' EWOLIE bits ------- EWOLIE_UCWOLIE = (1<<7) EWOLIE_AWOLIE = (1<<6) EWOLIE_PMWOLIE = (1<<4) EWOLIE_MPWOLIE = (1<<3) EWOLIE_HTWOLIE = (1<<2) EWOLIE_MCWOLIE = (1<<1) EWOLIE_BCWOLIE = (1) ' EWOLIR bits ------- EWOLIR_UCWOLIF = (1<<7) EWOLIR_AWOLIF = (1<<6) EWOLIR_PMWOLIF = (1<<4) EWOLIR_MPWOLIF = (1<<3) EWOLIR_HTWOLIF = (1<<2) EWOLIR_MCWOLIF = (1<<1) EWOLIR_BCWOLIF = (1) ' ERXFCON bits ------ ERXFCON_UCEN = (1<<7) ERXFCON_ANDOR = (1<<6) ERXFCON_CRCEN = (1<<5) ERXFCON_PMEN = (1<<4) ERXFCON_MPEN = (1<<3) ERXFCON_HTEN = (1<<2) ERXFCON_MCEN = (1<<1) ERXFCON_BCEN = (1) ' MACON1 bits -------- MACON1_LOOPBK = (1<<4) MACON1_TXPAUS = (1<<3) MACON1_RXPAUS = (1<<2) MACON1_PASSALL = (1<<1) MACON1_MARXEN = (1) ' MACON2 bits -------- MACON2_MARST = (1<<7) MACON2_RNDRST = (1<<6) MACON2_MARXRST = (1<<3) MACON2_RFUNRST = (1<<2) MACON2_MATXRST = (1<<1) MACON2_TFUNRST = (1) ' MACON3 bits -------- MACON3_PADCFG2 = (1<<7) MACON3_PADCFG1 = (1<<6) MACON3_PADCFG0 = (1<<5) MACON3_TXCRCEN = (1<<4) MACON3_PHDRLEN = (1<<3) MACON3_HFRMEN = (1<<2) MACON3_FRMLNEN = (1<<1) MACON3_FULDPX = (1) ' MACON4 bits -------- MACON4_DEFER = (1<<6) MACON4_BPEN = (1<<5) MACON4_NOBKOFF = (1<<4) MACON4_LONGPRE = (1<<1) MACON4_PUREPRE = (1) ' MAPHSUP bits ---- MAPHSUP_RSTRMII = (1<<3) ' MICON bits -------- MICON_RSTMII = (1<<7) ' MICMD bits --------- MICMD_MIISCAN = (1<<1) MICMD_MIIRD = (1) ' EBSTCON bits ----- EBSTCON_PSV2 = (1<<7) EBSTCON_PSV1 = (1<<6) EBSTCON_PSV0 = (1<<5) EBSTCON_PSEL = (1<<4) EBSTCON_TMSEL1 = (1<<3) EBSTCON_TMSEL0 = (1<<2) EBSTCON_TME = (1<<1) EBSTCON_BISTST = (1) ' MISTAT bits -------- MISTAT_NVALID = (1<<2) MISTAT_SCAN = (1<<1) MISTAT_BUSY = (1) ' ECOCON bits ------- ECOCON_COCON2 = (1<<2) ECOCON_COCON1 = (1<<1) ECOCON_COCON0 = (1) ' EFLOCON bits ----- EFLOCON_FULDPXS = (1<<2) EFLOCON_FCEN1 = (1<<1) EFLOCON_FCEN0 = (1) ' PHY bits ' PHCON1 bits ---------- PHCON1_PRST = (1<<15) PHCON1_PLOOPBK = (1<<14) PHCON1_PPWRSV = (1<<11) PHCON1_PDPXMD = (1<<8) ' PHSTAT1 bits -------- PHSTAT1_PFDPX = (1<<12) PHSTAT1_PHDPX = (1<<11) PHSTAT1_LLSTAT = (1<<2) PHSTAT1_JBSTAT = (1<<1) ' PHID2 bits -------- PHID2_PID24 = (1<<15) PHID2_PID23 = (1<<14) PHID2_PID22 = (1<<13) PHID2_PID21 = (1<<12) PHID2_PID20 = (1<<11) PHID2_PID19 = (1<<10) PHID2_PPN5 = (1<<9) PHID2_PPN4 = (1<<8) PHID2_PPN3 = (1<<7) PHID2_PPN2 = (1<<6) PHID2_PPN1 = (1<<5) PHID2_PPN0 = (1<<4) PHID2_PREV3 = (1<<3) PHID2_PREV2 = (1<<2) PHID2_PREV1 = (1<<1) PHID2_PREV0 = (1) ' PHCON2 bits ---------- PHCON2_FRCLNK = (1<<14) PHCON2_TXDIS = (1<<13) PHCON2_JABBER = (1<<10) PHCON2_HDLDIS = (1<<8) ' PHSTAT2 bits -------- PHSTAT2_TXSTAT = (1<<13) PHSTAT2_RXSTAT = (1<<12) PHSTAT2_COLSTAT = (1<<11) PHSTAT2_LSTAT = (1<<10) PHSTAT2_DPXSTAT = (1<<9) PHSTAT2_PLRITY = (1<<5) ' PHIE bits ----------- PHIE_PLNKIE = (1<<4) PHIE_PGEIE = (1<<1) ' PHIR bits ----------- PHIR_PLNKIF = (1<<4) PHIR_PGIF = (1<<2) ' PHLCON bits ------- PHLCON_LACFG3 = (1<<11) PHLCON_LACFG2 = (1<<10) PHLCON_LACFG1 = (1<<9) PHLCON_LACFG0 = (1<<8) PHLCON_LBCFG3 = (1<<7) PHLCON_LBCFG2 = (1<<6) PHLCON_LBCFG1 = (1<<5) PHLCON_LBCFG0 = (1<<4) PHLCON_LFRQ1 = (1<<3) PHLCON_LFRQ0 = (1<<2) PHLCON_STRCH = (1<<1) \ No newline at end of file diff --git a/lib/driver_socket.spin b/lib/driver_socket.spin new file mode 100644 index 0000000..dd75d88 --- /dev/null +++ b/lib/driver_socket.spin @@ -0,0 +1 @@ +{{ Ethernet TCP/IP Socket Layer Driver (IPv4) ------------------------------------------ Copyright (c) 2006-2009 Harrison Pham Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The latest version of this software can be obtained from http://hdpham.com/PropTCP and http://obex.parallax.com/}}'' NOTICE: All buffer sizes must be a power of 2!CON' ***************************************' ** Versioning Information **' *************************************** version = 5 ' major version release = 2 ' minor version apiversion = 8 ' api compatibility version' ***************************************' ** User Definable Settings **' *************************************** sNumSockets = 4 ' max number of concurrent registered sockets (max of 255)' *** End of user definable settings, don't edit anything below this line!!!' *** All IP/MAC settings are defined by calling the start(...) methodCON' ***************************************' ** Return Codes / Errors **' *************************************** RETBUFFEREMPTY = -1 ' no data available RETBUFFERFULL = -1 ' buffer full ERRGENERIC = -1 ' generic errors ERR = -100 ' error codes start at -100 ERRBADHANDLE = ERR - 1 ' bad socket handle ERROUTOFSOCKETS = ERR - 2 ' no free sockets available ERRSOCKETCLOSED = ERR - 3 ' socket closed, could not perform operationOBJ nic : "driver_enc28j60" 'ser : "SerialMirror" 'stk : "Stack Length"CON' ***************************************' ** Socket Constants and Offsets **' ***************************************' Socket states (user should never touch these) SCLOSED = 0 ' closed, handle not used SLISTEN = 1 ' listening, in server mode SSYNSENT = 2 ' SYN sent, server mode, waits for ACK SSYNSENTCL = 3 ' SYN sent, client mode, waits for SYN+ACK SESTABLISHED = 4 ' established connection (either SYN+ACK, or ACK+Data) SCLOSING = 5 ' connection is being forced closed by code SCLOSING2 = 6 ' closing, we are waiting for a fin now SFORCECLOSE = 7 ' force connection close (just RSTs, no waiting for FIN or anything) SCONNECTINGARP1 = 8 ' connecting, next step: send arp request SCONNECTINGARP2 = 9 ' connecting, next step: arp request sent, waiting for response SCONNECTINGARP2G = 10 ' connecting, next step: arp request sent, waiting for response [GATEWAY REQUEST] SCONNECTING = 11 ' connecting, next step: got mac address, send SYN' ***************************************' ** TCP State Management Constants **' *************************************** TIMEOUTMS = 500 ' (milliseconds) timeout before a retransmit occurs RSTTIMEOUTMS = 2000 ' (milliseconds) timeout before a RST is sent to close the connection WINDOWUPDATEMS = 25 ' (milliseconds) window advertisement frequency MAXUNACKS = 6 ' max number of unacknowledged retransmits before the stack auto closes the socket ' timeout = TIMEOUTMS * MAXUNACKS (default: 500ms * 5 = 3000ms) EPHPORTSTART = 49152 ' ephemeral port start EPHPORTEND = 65535 ' end MAXPAYLOAD = 1200 ' maximum TCP payload (data) in bytes, this only applies when your txbuffer_length > payload sizeDAT' ***************************************' ** Global Variables **' *************************************** cog long 0 ' cog index (for stopping / starting) stack long 0[128] ' stack for new cog (currently ~74 longs, using 128 for expansion) mac_ptr long 0 ' mac address pointer pkt_id long 0 ' packet fragmentation id pkt_isn long 0 ' packet initial sequence number ip_ephport word 0 ' packet ephemeral port number (49152 to 65535) pkt_count byte 0 ' packet count lock_id byte 0 ' socket handle lock packet byte 0[nic#MAXFRAME] ' the ethernet frame' ***************************************' ** IP Address Defaults **' *************************************** ' NOTE: All of the MAC/IP variables here contain default values that will ' be used if override values are not provided as parameters in start(). long ' long alignment for addresses ip_addr byte 10, 10, 1, 4 ' device's ip address ip_subnet byte 255, 255, 255, 0 ' network subnet ip_gateway byte 10, 10, 1, 254 ' network gateway (router) ip_dns byte 10, 10, 1, 254 ' network dns ' ***************************************' ** Socket Data Arrays **' *************************************** long SocketArrayStart lMySeqNum long 0[sNumSockets] lMyAckNum long 0[sNumSockets] lSrcIp long 0[sNumSockets] lTime long 0[sNumSockets] word wSrcPort word 0[sNumSockets] wDstPort word 0[sNumSockets] wLastWin word 0[sNumSockets] wLastTxLen word 0[sNumSockets] wNotAcked word 0[sNumSockets] byte bSrcMac byte 0[sNumSockets * 6] bConState byte 0[sNumSockets] SocketArrayEnd ' ***************************************' ** Circular Buffer Arrays **' *************************************** word FifoDataStart rx_head word 0[sNumSockets] ' rx head array rx_tail word 0[sNumSockets] ' rx tail array tx_head word 0[sNumSockets] ' tx head array tx_tail word 0[sNumSockets] ' tx tail array tx_tailnew word 0[sNumSockets] ' the new tx_tail value (unacked data) rxbuffer_length word 0[sNumSockets] ' each socket's buffer sizes txbuffer_length word 0[sNumSockets] rxbuffer_mask word 0[sNumSockets] ' each socket's buffer masks for capping buffer sizes txbuffer_mask word 0[sNumSockets] long tx_bufferptr long 0[sNumSockets] ' pointer addresses to each socket's buffer spaces rx_bufferptr long 0[sNumSockets] FifoDataEnd PUB start(cs, sck, si, so, xtalout, macptr, ipconfigptr)'' Start the TCP/IP Stack (requires 2 cogs)'' Only call this once, otherwise you will get conflicts'' macptr = HUB memory pointer (address) to 6 contiguous mac address bytes'' ipconfigptr = HUB memory pointer (address) to ip configuration block (16 bytes)'' Must be in order: ip_addr, ip_subnet, ip_gateway, ip_dns stop 'stk.Init(@stack, 128) ' zero socket data arrays (clean up any dead stuff from previous instance) bytefill(@SocketArrayStart, 0, @SocketArrayEnd - @SocketArrayStart) ' reset buffer pointers, zeros a contigous set of bytes, starting at rx_head bytefill(@FifoDataStart, 0, @FifoDataEnd - @FifoDataStart) ' start new cog with tcp stack cog := cognew(engine(cs, sck, si, so, xtalout, macptr, ipconfigptr), @stack) + 1PUB stop'' Stop the driver if cog cogstop(cog~ - 1) ' stop the tcp engine nic.stop ' stop nic driver (kills spi engine) lockclr(lock_id) ' clear lock before returning it to the pool lockret(lock_id) ' return the lock to the lock poolPRI engine(cs, sck, si, so, xtalout, macptr, ipconfigptr) | i lock_id := locknew ' checkout a lock from the HUB lockclr(lock_id) ' clear the lock, just in case it was in a bad state ' Start the ENC28J60 driver in a new cog nic.start(cs, sck, si, so, xtalout, macptr) ' init the nic if ipconfigptr > -1 ' init ip configuration bytemove(@ip_addr, ipconfigptr, 16) mac_ptr := nic.get_mac_pointer ' get the local mac address pointer ip_ephport := EPHPORTSTART ' set initial ephemeral port number (might want to random seed this later) i := 0 nic.banksel(nic#EPKTCNT) ' select packet count bank repeat pkt_count := nic.rd_cntlreg(nic#EPKTCNT) if pkt_count > 0 service_packet ' handle packet nic.banksel(nic#EPKTCNT) ' re-select the packet count bank ++i if i > 10 ' perform send tick repeat while lockset(lock_id) tick_tcpsend ' occurs every 10 cycles, since incoming packets more important lockclr(lock_id) i := 0 nic.banksel(nic#EPKTCNT) ' re-select the packet count bankPRI service_packet ' lets process this frame nic.get_frame(@packet) ' check for arp packet type (highest priority obviously) if packet[enetpacketType0] == $08 AND packet[enetpacketType1] == $06 if packet[constant(arp_hwtype + 1)] == $01 AND packet[arp_prtype] == $08 AND packet[constant(arp_prtype + 1)] == $00 AND packet[arp_hwlen] == $06 AND packet[arp_prlen] == $04 if packet[arp_tipaddr] == ip_addr[0] AND packet[constant(arp_tipaddr + 1)] == ip_addr[1] AND packet[constant(arp_tipaddr + 2)] == ip_addr[2] AND packet[constant(arp_tipaddr + 3)] == ip_addr[3] case packet[constant(arp_op + 1)] $01 : handle_arp $02 : repeat while lockset(lock_id) handle_arpreply lockclr(lock_id) '++count_arp else if packet[enetpacketType0] == $08 AND packet[enetpacketType1] == $00 if packet[ip_destaddr] == ip_addr[0] AND packet[constant(ip_destaddr + 1)] == ip_addr[1] AND packet[constant(ip_destaddr + 2)] == ip_addr[2] AND packet[constant(ip_destaddr + 3)] == ip_addr[3] case packet[ip_proto] 'PROT_ICMP : 'handle_ping 'ser.str(stk.GetLength(0, 0)) 'stk.GetLength(30, 19200) '++count_ping PROT_TCP : repeat while lockset(lock_id) \handle_tcp ' handles abort out of tcp handlers (no socket found) lockclr(lock_id) '++count_tcp 'PROT_UDP : ++count_udp' *******************************' ** Protocol Receive Handlers **' *******************************PRI handle_arp | i nic.start_frame ' destination mac address repeat i from 0 to 5 nic.wr_frame(packet[enetpacketSrc0 + i]) ' source mac address repeat i from 0 to 5 nic.wr_frame(BYTE[mac_ptr][i]) nic.wr_frame($08) ' arp packet nic.wr_frame($06) nic.wr_frame($00) ' 10mb ethernet nic.wr_frame($01) nic.wr_frame($08) ' ip proto nic.wr_frame($00) nic.wr_frame($06) ' mac addr len nic.wr_frame($04) ' proto addr len nic.wr_frame($00) ' arp reply nic.wr_frame($02) ' write ethernet module mac address repeat i from 0 to 5 nic.wr_frame(BYTE[mac_ptr][i]) ' write ethernet module ip address repeat i from 0 to 3 nic.wr_frame(ip_addr[i]) ' write remote mac address repeat i from 0 to 5 nic.wr_frame(packet[enetpacketSrc0 + i]) ' write remote ip address repeat i from 0 to 3 nic.wr_frame(packet[arp_sipaddr + i]) return nic.send_framePRI handle_arpreply | handle, ip, found ' Gets arp reply if it is a response to an ip we have ip := (packet[constant(arp_sipaddr + 3)] << 24) + (packet[constant(arp_sipaddr + 2)] << 16) + (packet[constant(arp_sipaddr + 1)] << 8) + (packet[arp_sipaddr]) found := false if ip == LONG[@ip_gateway] ' find a handle that wants gateway mac repeat handle from 0 to constant(sNumSockets - 1) if bConState[handle] == SCONNECTINGARP2G found := true quit else ' find the one that wants this arp repeat handle from 0 to constant(sNumSockets - 1) if bConState[handle] == SCONNECTINGARP2 if lSrcIp[handle] == ip found := true quit if found bytemove(@bSrcMac[handle * 6], @packet + arp_shaddr, 6) bConState[handle] := SCONNECTING'PRI handle_ping ' Not implemented yet (save on space!) PRI handle_tcp | i, ptr, handle, srcip, dstport, srcport, datain_len ' Handles incoming TCP packets srcip := packet[ip_srcaddr] << 24 + packet[constant(ip_srcaddr + 1)] << 16 + packet[constant(ip_srcaddr + 2)] << 8 + packet[constant(ip_srcaddr + 3)] dstport := packet[TCP_destport] << 8 + packet[constant(TCP_destport + 1)] srcport := packet[TCP_srcport] << 8 + packet[constant(TCP_srcport + 1)] handle := find_socket(srcip, dstport, srcport) ' if no sockets avail, it will abort out of this function ' at this point we assume we have an active socket, or a socket available to be used datain_len := ((packet[ip_pktlen] << 8) + packet[constant(ip_pktlen + 1)]) - ((packet[ip_vers_len] & $0F) * 4) - (((packet[TCP_hdrlen] & $F0) >> 4) * 4) if (bConState[handle] == SSYNSENT OR bConState[handle] == SESTABLISHED) AND (packet[TCP_hdrflags] & TCP_ACK) AND datain_len > 0 ' ACK, without SYN, with data ' set socket state, established session bConState[handle] := SESTABLISHED i := packet[constant(TCP_seqnum + 3)] << 24 + packet[constant(TCP_seqnum + 2)] << 16 + packet[constant(TCP_seqnum + 1)] << 8 + packet[TCP_seqnum] if lMyAckNum[handle] == i if datain_len =< (rxbuffer_mask[handle] - ((rx_head[handle] - rx_tail[handle]) & rxbuffer_mask[handle])) ' we have buffer space ptr := rx_bufferptr[handle] if (datain_len + rx_head[handle]) > rxbuffer_length[handle] bytemove(ptr + rx_head[handle], @packet[TCP_data], rxbuffer_length[handle] - rx_head[handle]) bytemove(ptr, @packet[TCP_data] + (rxbuffer_length[handle] - rx_head[handle]), datain_len - (rxbuffer_length[handle] - rx_head[handle])) else bytemove(ptr + rx_head[handle], @packet[TCP_data], datain_len) rx_head[handle] := (rx_head[handle] + datain_len) & rxbuffer_mask[handle] else datain_len := 0 else ' we had a bad ack number, meaning lost or out of order packet ' we have to wait for the remote host to retransmit in order datain_len := 0 ' recalculate ack number lMyAckNum[handle] := conv_endianlong(conv_endianlong(lMyAckNum[handle]) + datain_len) ' ACK response build_ipheaderskeleton(handle) build_tcpskeleton(handle, TCP_ACK) send_tcpfinal(handle, 0) elseif (bConState[handle] == SSYNSENTCL) AND (packet[TCP_hdrflags] & TCP_SYN) AND (packet[TCP_hdrflags] & TCP_ACK) ' We got a server response, so we ACK it bytemove(@lMySeqNum[handle], @packet + TCP_acknum, 4) bytemove(@lMyAckNum[handle], @packet + TCP_seqnum, 4) lMyAckNum[handle] := conv_endianlong(conv_endianlong(lMyAckNum[handle]) + 1) ' ACK response build_ipheaderskeleton(handle) build_tcpskeleton(handle, TCP_ACK) send_tcpfinal(handle, 0) ' set socket state, established session bConState[handle] := SESTABLISHED elseif (bConState[handle] == SLISTEN) AND (packet[TCP_hdrflags] & TCP_SYN) ' Reply to SYN with SYN + ACK ' copy mac address so we don't have to keep an ARP table bytemove(@bSrcMac[handle * 6], @packet + enetpacketSrc0, 6) ' copy ip, port data bytemove(@lSrcIp[handle], @packet + ip_srcaddr, 4) bytemove(@wSrcPort[handle], @packet + TCP_srcport, 2) bytemove(@wDstPort[handle], @packet + TCP_destport, 2) ' get updated ack numbers bytemove(@lMyAckNum[handle], @packet + TCP_seqnum, 4) lMyAckNum[handle] := conv_endianlong(conv_endianlong(lMyAckNum[handle]) + 1) lMySeqNum[handle] := conv_endianlong(++pkt_isn) ' Initial seq num (random) build_ipheaderskeleton(handle) build_tcpskeleton(handle, constant(TCP_SYN | TCP_ACK)) send_tcpfinal(handle, 0) ' incremement the sequence number for the next packet (it will be for an established connection) lMySeqNum[handle] := conv_endianlong(conv_endianlong(lMySeqNum[handle]) + 1) ' set socket state, waiting for establish bConState[handle] := SSYNSENT elseif (bConState[handle] == SESTABLISHED OR bConState[handle] == SCLOSING2) AND (packet[TCP_hdrflags] & TCP_FIN) ' Reply to FIN with RST ' get updated sequence and ack numbers (gaurantee we have correct ones to kill connection with) bytemove(@lMySeqNum[handle], @packet + TCP_acknum, 4) bytemove(@lMyAckNum[handle], @packet + TCP_seqnum, 4) 'LONG[handle_addr + sMyAckNum] := conv_endianlong(conv_endianlong(LONG[handle_addr + sMyAckNum]) + 1) build_ipheaderskeleton(handle) build_tcpskeleton(handle, TCP_RST) send_tcpfinal(handle, 0) ' set socket state, now free bConState[handle] := SCLOSED return elseif (bConState[handle] == SSYNSENT) AND (packet[TCP_hdrflags] & TCP_ACK) ' if just an ack, and we sent a syn before, then it's established ' this just gives us the ability to send on connect bConState[handle] := SESTABLISHED elseif (packet[TCP_hdrflags] & TCP_RST) ' Reset, reset states bConState[handle] := SCLOSED return if (bConState[handle] == SESTABLISHED OR bConState[handle] == SCLOSING) AND (packet[TCP_hdrflags] & TCP_ACK) wNotAcked[handle] := 0 ' reset retransmit counter ' check to see if our last sent data has been ack'd i := packet[TCP_acknum] << 24 + packet[constant(TCP_acknum + 1)] << 16 + packet[constant(TCP_acknum + 2)] << 8 + packet[constant(TCP_acknum + 3)] if i == (conv_endianlong(lMySeqNum[handle]) + wLastTxLen[handle]) ' we received an ack for our last sent packet, so we update our sequence number and buffer pointers lMySeqNum[handle] := conv_endianlong(conv_endianlong(lMySeqNum[handle]) + wLastTxLen[handle]) tx_tail[handle] := tx_tailnew[handle] wLastTxLen[handle] := 0 tcpsend(handle) ' send dataPRI build_ipheaderskeleton(handle) | hdrlen, hdr_chksum bytemove(@packet + ip_destaddr, @lSrcIp[handle], 4) ' Set destination address bytemove(@packet + ip_srcaddr, @ip_addr, 4) ' Set source address bytemove(@packet + enetpacketDest0, @bSrcMac[handle * 6], 6) ' Set destination mac address bytemove(@packet + enetpacketSrc0, mac_ptr, 6) ' Set source mac address packet[enetpacketType0] := $08 packet[constant(enetpacketType0 + 1)] := $00 packet[ip_vers_len] := $45 packet[ip_tos] := $00 ++pkt_id packet[ip_id] := pkt_id >> 8 ' Used for fragmentation packet[constant(ip_id + 1)] := pkt_id packet[ip_frag_offset] := $40 ' Don't fragment packet[constant(ip_frag_offset + 1)] := 0 packet[ip_ttl] := $80 ' TTL = 128 packet[ip_proto] := $06 ' TCP protocolPRI build_tcpskeleton(handle, flags) | size bytemove(@packet + TCP_srcport, @wDstPort[handle], 2) ' Source port bytemove(@packet + TCP_destport, @wSrcPort[handle], 2) ' Destination port bytemove(@packet + TCP_seqnum, @lMySeqNum[handle], 4) ' Seq Num bytemove(@packet + TCP_acknum, @lMyAckNum[handle], 4) ' Ack Num packet[TCP_hdrlen] := $50 ' Header length packet[TCP_hdrflags] := flags ' TCP state flags ' we have to recalculate the window size often otherwise our stack ' might explode from too much data :( size := (rxbuffer_mask[handle] - ((rx_head[handle] - rx_tail[handle]) & rxbuffer_mask[handle])) wLastWin[handle] := size packet[TCP_window] := (size & $FF00) >> 8 packet[constant(TCP_window + 1)] := size & $FF PRI send_tcpfinal(handle, datalen) | i, tcplen, hdrlen, hdr_chksum tcplen := 40 + datalen ' real length = data + headers packet[ip_pktlen] := tcplen >> 8 packet[constant(ip_pktlen + 1)] := tcplen ' calc ip header checksum packet[ip_hdr_cksum] := $00 packet[constant(ip_hdr_cksum + 1)] := $00 hdrlen := (packet[ip_vers_len] & $0F) * 4 hdr_chksum := calc_chksum(@packet[ip_vers_len], hdrlen) packet[ip_hdr_cksum] := hdr_chksum >> 8 packet[constant(ip_hdr_cksum + 1)] := hdr_chksum ' calc checksum packet[TCP_cksum] := $00 packet[constant(TCP_cksum + 1)] := $00 hdr_chksum := nic.chksum_add(@packet[ip_srcaddr], 8) hdr_chksum += packet[ip_proto] i := tcplen - ((packet[ip_vers_len] & $0F) * 4) hdr_chksum += i hdr_chksum += nic.chksum_add(@packet[TCP_srcport], i) hdr_chksum := calc_chksumfinal(hdr_chksum) packet[TCP_cksum] := hdr_chksum >> 8 packet[constant(TCP_cksum + 1)] := hdr_chksum tcplen += 14 if tcplen < 60 tcplen := 60 ' protect from buffer overrun if tcplen => nic#TX_BUFFER_SIZE return ' send the packet nic.start_frame nic.wr_block(@packet, tcplen) nic.send_frame lTime[handle] := cnt ' update last sent time (for timeout detection) PRI find_socket(srcip, dstport, srcport) | handle, free_handle, listen_handle ' Search for socket, matches ip address, port states ' Returns handle address (start memory location of socket) ' If no matches, will abort with -1 ' If supplied with srcip = 0 then will return free unused handle, aborts with -1 if none avail free_handle := -1 listen_handle := -1 repeat handle from 0 to constant(sNumSockets - 1) if bConState[handle] <> SCLOSED if (lSrcIp[handle] == 0) OR (lSrcIp[handle] == conv_endianlong(srcip)) ' ip match, ip socket srcip = 0, then will try to match dst port (find listening socket) if (wDstPort[handle] == conv_endianword(dstport)) {AND (WORD[handle_addr + sSrcPort] == 0 OR WORD[handle_addr + sSrcPort] == conv_endianword(srcport))} if wSrcPort[handle] == conv_endianword(srcport) ' found exact socket match (established socket) return handle elseif wSrcPort[handle] == 0 ' found a partial match (listening socket with no peer) listen_handle := handle elseif srcip == 0 ' found a closed (unallocated) socket, save this as a free handle if we are searching for a free handle free_handle := handle ' we found a free handle, may need this later if srcip <> 0 ' return the listening handle we found if listen_handle <> -1 return listen_handle else ' searched for a free handle if free_handle <> -1 return free_handle ' could not find a matching socket / free socket... abort -1' ******************************' ** Transmit Buffer Handlers **' ******************************PRI tcpsend(handle) | ptr, len ' Check buffers for data to send (called in main loop) if tx_tail[handle] == tx_head[handle] ' no data in buffer, so just quit return ' we have data to send, so send it ptr := tx_bufferptr[handle] len := ((tx_head[handle] - tx_tail[handle]) & txbuffer_mask[handle]) <# MAXPAYLOAD if (len + tx_tail[handle]) > txbuffer_length[handle] bytemove(@packet[TCP_data], ptr + tx_tail[handle], txbuffer_length[handle] - tx_tail[handle]) bytemove(@packet[TCP_data] + (txbuffer_length[handle] - tx_tail[handle]), ptr, len - (txbuffer_length[handle] - tx_tail[handle])) else bytemove(@packet[TCP_data], ptr + tx_tail[handle], len) tx_tailnew[handle] := (tx_tail[handle] + len) & txbuffer_mask[handle] wLastTxLen[handle] := len build_ipheaderskeleton(handle) build_tcpskeleton(handle, TCP_ACK {constant(TCP_ACK | TCP_PSH)}) send_tcpfinal(handle, len) ' send actual data send_tcpfinal(handle, 0) ' send an empty packet to force the other side to ACK (hack to get around delayed acks) wNotAcked[handle]++ ' increment unacked packet counter PRI tick_tcpsend | handle, state, len repeat handle from 0 to constant(sNumSockets - 1) state := bConState[handle] if state == SESTABLISHED OR state == SCLOSING len := (rxbuffer_mask[handle] - ((rx_head[handle] - rx_tail[handle]) & rxbuffer_mask[handle])) if wLastWin[handle] <> len AND len => (rxbuffer_length[handle] / 2) AND ((cnt - lTime[handle]) / (clkfreq / 1000) > WINDOWUPDATEMS) ' update window size build_ipheaderskeleton(handle) build_tcpskeleton(handle, TCP_ACK) send_tcpfinal(handle, 0) if ((cnt - lTime[handle]) / (clkfreq / 1000) > TIMEOUTMS) OR wLastTxLen[handle] == 0 ' send new data OR retransmit our last packet since the other side seems to have lost it ' the remote host will respond with another dup ack, and we will get back on track (hopefully) tcpsend(handle) if (state == SCLOSING) build_ipheaderskeleton(handle) build_tcpskeleton(handle, constant(TCP_ACK | TCP_FIN)) send_tcpfinal(handle, 0) ' we now wait for the other side to terminate bConState[handle] := SCLOSING2 elseif state == SCONNECTINGARP1 ' We need to send an arp request arp_request_checkgateway(handle) elseif state == SCONNECTING ' Yea! We got an arp response previously, so now we can send the SYN lMySeqNum[handle] := conv_endianlong(++pkt_isn) lMyAckNum[handle] := 0 build_ipheaderskeleton(handle) build_tcpskeleton(handle, TCP_SYN) send_tcpfinal(handle, 0) bConState[handle] := SSYNSENTCL elseif (state == SFORCECLOSE) OR (state == SESTABLISHED AND wNotAcked[handle] => MAXUNACKS) OR (lookdown(state: SCLOSING2, SSYNSENT, SSYNSENTCL, SCONNECTINGARP2, SCONNECTINGARP2G) {(state == SCLOSING2 OR state == SSYNSENT)} AND ((cnt - lTime[handle]) / (clkfreq / 1000) > RSTTIMEOUTMS)) ' Force close (send RST, and say the socket is closed!) ' This is triggered when any of the following happens: ' 1 - we don't get a response to our SSYNSENT state ' 2 - we exceeded MAXUNACKS tcp retransmits (remote host lost) ' 3 - we get stuck in the SSCLOSING2 state ' 4 - we don't get a response to our client SYNSENTCL state ' 5 - we don't get an ARP response state SCONNECTINGARP2 or SCONNECTINGARP2G build_ipheaderskeleton(handle) build_tcpskeleton(handle, TCP_RST) send_tcpfinal(handle, 0) bConState[handle] := SCLOSEDPRI arp_request_checkgateway(handle) | ip_ptr ip_ptr := @lSrcIp[handle] if (BYTE[ip_ptr] & ip_subnet[0]) == (ip_addr[0] & ip_subnet[0]) AND (BYTE[ip_ptr + 1] & ip_subnet[1]) == (ip_addr[1] & ip_subnet[1]) AND (BYTE[ip_ptr + 2] & ip_subnet[2]) == (ip_addr[2] & ip_subnet[2]) AND (BYTE[ip_ptr + 3] & ip_subnet[3]) == (ip_addr[3] & ip_subnet[3]) arp_request(conv_endianlong(LONG[ip_ptr])) bConState[handle] := SCONNECTINGARP2 else arp_request(conv_endianlong(LONG[@ip_gateway])) bConState[handle] := SCONNECTINGARP2G lTime[handle] := cnt PRI arp_request(ip) | i nic.start_frame ' destination mac address (broadcast mac) repeat i from 0 to 5 nic.wr_frame($FF) ' source mac address (this device) repeat i from 0 to 5 nic.wr_frame(BYTE[mac_ptr][i]) nic.wr_frame($08) ' arp packet nic.wr_frame($06) nic.wr_frame($00) ' 10mb ethernet nic.wr_frame($01) nic.wr_frame($08) ' ip proto nic.wr_frame($00) nic.wr_frame($06) ' mac addr len nic.wr_frame($04) ' proto addr len nic.wr_frame($00) ' arp request nic.wr_frame($01) ' source mac address (this device) repeat i from 0 to 5 nic.wr_frame(BYTE[mac_ptr][i]) ' source ip address (this device) repeat i from 0 to 3 nic.wr_frame(ip_addr[i]) ' unknown mac address area repeat i from 0 to 5 nic.wr_frame($00) ' figure out if we need router arp request or host arp request ' this means some subnet masking ' dest ip address repeat i from 3 to 0 nic.wr_frame(ip.byte[i]) ' send the request return nic.send_frame ' *******************************' ** IP Packet Helpers (Calcs) **' ******************************* PRI calc_chksum(ptr, hdrlen) : chksum ' Calculates IP checksums ' packet = pointer to IP packet ' returns: chksum ' http://www.geocities.com/SiliconValley/2072/bit33.txt 'chksum := calc_chksumhalf(packet, hdrlen) chksum := nic.chksum_add(ptr, hdrlen) chksum := calc_chksumfinal(chksum)PRI calc_chksumfinal(chksumin) : chksum ' Performs the final part of checksums chksum := (chksumin >> 16) + (chksumin & $FFFF) chksum := (!chksum) & $FFFF {PRI calc_chksumhalf(packet, hdrlen) : chksum ' Calculates checksum without doing the final stage of calculations chksum := 0 repeat while hdrlen > 1 chksum += (BYTE[packet++] << 8) + BYTE[packet++] chksum := (chksum >> 16) + (chksum & $FFFF) hdrlen -= 2 if hdrlen > 0 chksum += BYTE[packet] << 8}' ***************************' ** Memory Access Helpers **' *************************** PRI conv_endianlong(in) 'return (in << 24) + ((in & $FF00) << 8) + ((in & $FF0000) >> 8) + (in >> 24) ' we can sometimes get away with shifting without masking, since shifts kill extra bits anyways return (in.byte[0] << 24) + (in.byte[1] << 16) + (in.byte[2] << 8) + (in.byte[3]) PRI conv_endianword(in) 'return ((in & $FF) << 8) + ((in & $FF00) >> 8) return (in.byte[0] << 8) + (in.byte[1])PRI _handleConvert(userHandle, ptrHandle) | handle' Checks to see if a handle index is valid' Aborts if the handle is invalid handle := userHandle.byte[0] ' extract the handle index from the lower 8 bits if handle < 0 OR handle > constant(sNumSockets - 1) ' check the handle index to make sure we don't go out of bounds abort ERRBADHANDLE ' check handle to make sure it's the one we want (rid ourselves of bad user handles) ' the current check method is as follows: ' - compare sDstPort if wDstPort[handle] <> ((userHandle.byte[2] << 8) + userHandle.byte[1]) abort ERRBADHANDLE ' if we got here without aborting then we can assume the handle is good LONG[ptrHandle] := handle' ************************************' ** Public Accessors (Thread Safe) **' ************************************PUB listen(port, _ptrrxbuff, _rxlen, _ptrtxbuff, _txlen) | handle'' Sets up a socket for listening on a port'' port = port number to listen on'' ptrrxbuff = pointer to the rxbuffer array'' rxlen = length of the rxbuffer array (must be power of 2)'' ptrtxbuff = pointer to the txbuffer array'' txlen = length of the txbuffer array (must be power of 2)'' Returns handle if available, ERROUTOFSOCKETS if none available'' Nonblocking repeat while lockset(lock_id) ' just find any avail closed socket handle := \find_socket(0, 0, 0) if handle < 0 lockclr(lock_id) abort ERROUTOFSOCKETS rx_bufferptr[handle] := _ptrrxbuff tx_bufferptr[handle] := _ptrtxbuff rxbuffer_length[handle] := _rxlen txbuffer_length[handle] := _txlen rxbuffer_mask[handle] := _rxlen - 1 txbuffer_mask[handle] := _txlen - 1 lMySeqNum[handle] := 0 lMyAckNum[handle] := 0 lSrcIp[handle] := 0 lTime[handle] := 0 wLastTxLen[handle] := 0 wNotAcked[handle] := 0 bytefill(@bSrcMac[handle * 6], 0, 6) wSrcPort[handle] := 0 ' no source port yet wDstPort[handle] := conv_endianword(port) ' we do have a dest port though wLastWin[handle] := rxbuffer_length[handle] tx_head[handle] := 0 tx_tail[handle] := 0 tx_tailnew[handle] := 0 rx_head[handle] := 0 rx_tail[handle] := 0 ' it's now listening bConState[handle] := SLISTEN lockclr(lock_id) return ((port.byte[0] << 16) + (port.byte[1] << 8)) + handle PUB connect(ipaddr, remoteport, _ptrrxbuff, _rxlen, _ptrtxbuff, _txlen) | handle, user_handle'' Connect to remote host'' ipaddr = ipv4 address packed into a long (ie: 1.2.3.4 => $01_02_03_04)'' remoteport = port number to connect to'' ptrrxbuff = pointer to the rxbuffer array'' rxlen = length of the rxbuffer array (must be power of 2)'' ptrtxbuff = pointer to the txbuffer array'' txlen = length of the txbuffer array (must be power of 2)'' Returns handle to new socket, ERROUTOFSOCKETS if no socket available'' Nonblocking repeat while lockset(lock_id) ' just find any avail closed socket handle := \find_socket(0, 0, 0) if handle < 0 lockclr(lock_id) abort ERROUTOFSOCKETS rx_bufferptr[handle] := _ptrrxbuff tx_bufferptr[handle] := _ptrtxbuff rxbuffer_length[handle] := _rxlen txbuffer_length[handle] := _txlen rxbuffer_mask[handle] := _rxlen - 1 txbuffer_mask[handle] := _txlen - 1 lMySeqNum[handle] := 0 lMyAckNum[handle] := 0 lTime[handle] := 0 wLastTxLen[handle] := 0 wNotAcked[handle] := 0 bytefill(@bSrcMac[handle * 6], 0, 6) if(ip_ephport => EPHPORTEND) ' constrain ephport to specified range ip_ephport := EPHPORTSTART user_handle := ((ip_ephport.byte[0] << 16) + (ip_ephport.byte[1] << 8)) + handle ' copy in ip, port data (with respect to the remote host, since we use same code as server) lSrcIp[handle] := conv_endianlong(ipaddr) wSrcPort[handle] := conv_endianword(remoteport) wDstPort[handle] := conv_endianword(ip_ephport++) wLastWin[handle] := rxbuffer_length[handle] tx_head[handle] := 0 tx_tail[handle] := 0 tx_tailnew[handle] := 0 rx_head[handle] := 0 rx_tail[handle] := 0 bConState[handle] := SCONNECTINGARP1 lockclr(lock_id) return user_handlePUB close(user_handle) | handle, state'' Closes a connection _handleConvert(user_handle, @handle) repeat while lockset(lock_id) state := bConState[handle] if state == SESTABLISHED ' try to gracefully close the connection bConState[handle] := SCLOSING elseif state <> SCLOSING AND state <> SCLOSING2 ' we only do an ungraceful close if we are not in ESTABLISHED, CLOSING, or CLOSING2 bConState[handle] := SCLOSED lockclr(lock_id) ' wait for the socket to close, this is very important to prevent the client app from reusing the buffers repeat until (bConState[handle] == SCLOSING2) or (bConState[handle] == SCLOSED)PUB isConnected(user_handle) | handle'' Returns true if the socket is connected, false otherwise if \_handleConvert(user_handle, @handle) <> 0 return false return (bConState[handle] == SESTABLISHED) PUB isValidHandle(user_handle) | handle'' Checks to see if the handle is valid, handles will become invalid once they are used'' In other words, a closed listening socket is now invalid, etc {if handle < 0 OR handle > constant(sNumSockets - 1) ' obviously the handle index is out of range, so it's not valid! return false} if \_handleConvert(user_handle, @handle) < 0 return false return (bConState[handle] <> SCLOSED)PUB readDataNonBlocking(user_handle, ptr, maxlen) | handle, len, rxptr'' Reads bytes from the socket'' Returns number of read bytes'' Not blocking (returns RETBUFFEREMPTY if no data) _handleConvert(user_handle, @handle) if rx_tail[handle] == rx_head[handle] return RETBUFFEREMPTY len := (rx_head[handle] - rx_tail[handle]) & rxbuffer_mask[handle] if maxlen < len len := maxlen rxptr := rx_bufferptr[handle] if (len + rx_tail[handle]) > rxbuffer_length[handle] bytemove(ptr, rxptr + rx_tail[handle], rxbuffer_length[handle] - rx_tail[handle]) bytemove(ptr + (rxbuffer_length[handle] - rx_tail[handle]), rxptr, len - (rxbuffer_length[handle] - rx_tail[handle])) else bytemove(ptr, rxptr + rx_tail[handle], len) rx_tail[handle] := (rx_tail[handle] + len) & rxbuffer_mask[handle] return len PUB readData(user_handle, ptr, maxlen) : len | handle'' Reads bytes from the socket'' Returns the number of read bytes'' Will block until data is received _handleConvert(user_handle, @handle) repeat while (len := readDataNonBlocking(user_handle, ptr, maxlen)) < 0 ifnot isConnected(user_handle) abort ERRSOCKETCLOSEDPUB readByteNonBlocking(user_handle) : rxbyte | handle, ptr'' Read a byte from the specified socket'' Will not block (returns RETBUFFEREMPTY if no byte avail) _handleConvert(user_handle, @handle) rxbyte := RETBUFFEREMPTY if rx_tail[handle] <> rx_head[handle] ptr := rx_bufferptr[handle] rxbyte := BYTE[ptr][rx_tail[handle]] rx_tail[handle] := (rx_tail[handle] + 1) & rxbuffer_mask[handle] PUB readByte(user_handle) : rxbyte | handle, ptr'' Read a byte from the specified socket'' Will block until a byte is received _handleConvert(user_handle, @handle) repeat while (rxbyte := readByteNonBlocking(user_handle)) < 0 ifnot isConnected(user_handle) abort ERRSOCKETCLOSEDPUB writeDataNonBlocking(user_handle, ptr, len) | handle, txptr'' Writes bytes to the socket'' Will not write anything unless your data fits in the buffer'' Non blocking (returns RETBUFFERFULL if can't fit data) _handleConvert(user_handle, @handle) if (txbuffer_mask[handle] - ((tx_head[handle] - tx_tail[handle]) & txbuffer_mask[handle])) < len return RETBUFFERFULL txptr := tx_bufferptr[handle] if (len + tx_head[handle]) > txbuffer_length[handle] bytemove(txptr + tx_head[handle], ptr, txbuffer_length[handle] - tx_head[handle]) bytemove(txptr, ptr + (txbuffer_length[handle] - tx_head[handle]), len - (txbuffer_length[handle] - tx_head[handle])) else bytemove(txptr + tx_head[handle], ptr, len) tx_head[handle] := (tx_head[handle] + len) & txbuffer_mask[handle] return lenPUB writeData(user_handle, ptr, len) | handle'' Writes data to the specified socket'' Will block until all data is queued to be sent _handleConvert(user_handle, @handle) repeat while len > txbuffer_mask[handle] repeat while writeDataNonBlocking(user_handle, ptr, txbuffer_mask[handle]) < 0 ifnot isConnected(user_handle) abort ERRSOCKETCLOSED len -= txbuffer_mask[handle] ptr += txbuffer_mask[handle] repeat while writeDataNonBlocking(user_handle, ptr, len) < 0 ifnot isConnected(user_handle) abort ERRSOCKETCLOSEDPUB writeByteNonBlocking(user_handle, txbyte) | handle, ptr'' Writes a byte to the specified socket'' Will not block (returns RETBUFFERFULL if no buffer space available) _handleConvert(user_handle, @handle) ifnot (tx_tail[handle] <> (tx_head[handle] + 1) & txbuffer_mask[handle]) return RETBUFFERFULL ptr := tx_bufferptr[handle] BYTE[ptr][tx_head[handle]] := txbyte tx_head[handle] := (tx_head[handle] + 1) & txbuffer_mask[handle] return txbytePUB writeByte(user_handle, txbyte) | handle'' Write a byte to the specified socket'' Will block until space is available for byte to be sent _handleConvert(user_handle, @handle) repeat while writeByteNonBlocking(user_handle, txbyte) < 0 ifnot isConnected(user_handle) abort ERRSOCKETCLOSEDPUB resetBuffers(user_handle) | handle'' Resets send/receive buffers for the specified socket _handleConvert(user_handle, @handle) rx_tail[handle] := rx_head[handle] tx_head[handle] := tx_tail[handle]PUB flush(user_handle) | handle'' Flushes the send buffer (waits till the buffer is empty)'' Will block until all tx data is sent _handleConvert(user_handle, @handle) repeat while isConnected(user_handle) AND tx_tail[handle] <> tx_head[handle]PUB getSocketState(user_handle) | handle'' Gets the socket state (internal state numbers)'' You can include driver_socket in any object and use the S... state constants for comparison _handleConvert(user_handle, @handle) return bConState[handle]PUB getReceiveBufferCount(user_handle) | handle'' Returns the number of bytes in the receive buffer _handleConvert(user_handle, @handle) return (rx_head[handle] - rx_tail[handle]) & rxbuffer_mask[handle] CON '****************************************************************** '* TCP Flags '****************************************************************** TCP_FIN = 1 TCP_SYN = 2 TCP_RST = 4 TCP_PSH = 8 TCP_ACK = 16 TCP_URG = 32 TCP_ECE = 64 TCP_CWR = 128 '****************************************************************** '* Ethernet Header Layout '****************************************************************** enetpacketDest0 = $00 'destination mac address enetpacketDest1 = $01 enetpacketDest2 = $02 enetpacketDest3 = $03 enetpacketDest4 = $04 enetpacketDest5 = $05 enetpacketSrc0 = $06 'source mac address enetpacketSrc1 = $07 enetpacketSrc2 = $08 enetpacketSrc3 = $09 enetpacketSrc4 = $0A enetpacketSrc5 = $0B enetpacketType0 = $0C 'type/length field enetpacketType1 = $0D enetpacketData = $0E 'IP data area begins here '****************************************************************** '* ARP Layout '****************************************************************** arp_hwtype = $0E arp_prtype = $10 arp_hwlen = $12 arp_prlen = $13 arp_op = $14 arp_shaddr = $16 'arp source mac address arp_sipaddr = $1C 'arp source ip address arp_thaddr = $20 'arp target mac address arp_tipaddr = $26 'arp target ip address '****************************************************************** '* IP Header Layout '****************************************************************** ip_vers_len = $0E 'IP version and header length 1a19 ip_tos = $0F 'IP type of service ip_pktlen = $10 'packet length ip_id = $12 'datagram id ip_frag_offset = $14 'fragment offset ip_ttl = $16 'time to live ip_proto = $17 'protocol (ICMP=1, TCP=6, UDP=11) ip_hdr_cksum = $18 'header checksum 1a23 ip_srcaddr = $1A 'IP address of source ip_destaddr = $1E 'IP addess of destination ip_data = $22 'IP data area '****************************************************************** '* TCP Header Layout '****************************************************************** TCP_srcport = $22 'TCP source port TCP_destport = $24 'TCP destination port TCP_seqnum = $26 'sequence number TCP_acknum = $2A 'acknowledgement number TCP_hdrlen = $2E '4-bit header len (upper 4 bits) TCP_hdrflags = $2F 'TCP flags TCP_window = $30 'window size TCP_cksum = $32 'TCP checksum TCP_urgentptr = $34 'urgent pointer TCP_data = $36 'option/data '****************************************************************** '* IP Protocol Types '****************************************************************** PROT_ICMP = $01 PROT_TCP = $06 PROT_UDP = $11 '****************************************************************** '* ICMP Header '****************************************************************** ICMP_type = ip_data ICMP_code = ICMP_type+1 ICMP_cksum = ICMP_code+1 ICMP_id = ICMP_cksum+2 ICMP_seqnum = ICMP_id+2 ICMP_data = ICMP_seqnum+2 '****************************************************************** '* UDP Header '****************************************************************** UDP_srcport = ip_data UDP_destport = UDP_srcport+2 UDP_len = UDP_destport+2 UDP_cksum = UDP_len+2 UDP_data = UDP_cksum+2 '****************************************************************** '* DHCP Message '****************************************************************** DHCP_op = UDP_data DHCP_htype = DHCP_op+1 DHCP_hlen = DHCP_htype+1 DHCP_hops = DHCP_hlen+1 DHCP_xid = DHCP_hops+1 DHCP_secs = DHCP_xid+4 DHCP_flags = DHCP_secs+2 DHCP_ciaddr = DHCP_flags+2 DHCP_yiaddr = DHCP_ciaddr+4 DHCP_siaddr = DHCP_yiaddr+4 DHCP_giaddr = DHCP_siaddr+4 DHCP_chaddr = DHCP_giaddr+4 DHCP_sname = DHCP_chaddr+16 DHCP_file = DHCP_sname+64 DHCP_options = DHCP_file+128 DHCP_message_end = DHCP_options+312 \ No newline at end of file diff --git a/lib/glob-con.spin b/lib/glob-con.spin index 41ccdf7..cfeeb32 100644 --- a/lib/glob-con.spin +++ b/lib/glob-con.spin @@ -163,6 +163,13 @@ A_AYS = %00000000_00000000_00000010_00000000 a_rtcPauseForSec 'Pauses execution for a number of seconds. Returns a puesdo random value derived from the current clock frequency and the time when called. Number - Number of seconds to pause for between 0 and 2,147,483,647. a_rtcPauseForMSec '58 'Pauses execution for a number of milliseconds. Returns a puesdo random value derived from the current clock frequency and the time when called. Number - Number of milliseconds to pause for between 0 and 2,147,483,647. +' ---------------------------------------------- NET-FUNKTIONEN +#71, a_lanStart 'Start Network + a_lanStop 'Stop Network + a_lanFTPOpen 'FTP-Verbindung öffnen + a_lanFTPClose 'FTP-Verbindung schließen + a_lanFTPNextFile 'Verzeichniseintrag lesen + ' ---------------------------------------------- CHIP-MANAGMENT #92, a_mgrSetSound 'soundsubsysteme verwalten a_mgrGetSpec 'spezifikation abfragen diff --git a/lib/reg-ios.spin b/lib/reg-ios.spin index a76f073..b59a7d5 100644 --- a/lib/reg-ios.spin +++ b/lib/reg-ios.spin @@ -1026,7 +1026,21 @@ PUB pauseForMilliseconds(number) 'Pauses execution for a return bus_getlong1 +CON ''------------------------------------------------- LAN_LAUFWERKSFUNKTIONEN +PUB lanstart 'LAN starten +''funktionsgruppe : lan +''funktion : TCP-Netzwerk starten +''busprotokoll : - + + bus_putchar1(gc#a_lanStart) + +PUB lanstop 'LAN beenden +''funktionsgruppe : lan +''funktion : TCP-Netzwerk beenden +''busprotokoll : - + + bus_putchar1(gc#a_lanStop) CON ''------------------------------------------------- Hydra Sound System diff --git a/system/administra/admnet/admnet.spin b/system/administra/admnet/admnet.spin new file mode 100644 index 0000000..bdcfe63 --- /dev/null +++ b/system/administra/admnet/admnet.spin @@ -0,0 +1,1141 @@ +{{ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Autor: Ingo Kripahle & Jörg Deckert │ +│ Copyright (c) 2010 Ingo Kripahle, 2013 Jörg Deckert │ +│ See end of file for terms of use. │ +│ Die Nutzungsbedingungen befinden sich am Ende der Datei │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +Informationen : hive-project.de +Kontakt : drohne235@googlemail.com +System : TriOS +Name : Administra-Flash (LAN) +Chip : Administra +Typ : Flash +Version : 00 +Subversion : 01 + +Funktion : Diese Codeversion basiert auf admflash.spin und wird um einen LAN-Treiber erweitert. + Die Soundfunktionen wurden aus Platzgründen entfernt. + + Dieser Code wird von Administra nach einem Reset aus dem EEProm in den hRAM kopiert + und gestartet. Im Gegensatz zu Bellatrix und Regnatix, die einen Loader aus dem EEProm + laden und entsprechende Systemdateien vom SD-Cardlaufwerk booten, also im + wesentlichen vor dem Bootvorgang keine weiter Funktionalität als die Ladeprozedur + besitzen, muß das EEProm-Bios von Administra mindestens die Funktionalität des + SD-Cardlaufwerkes zur Verfügung stellen können. Es erscheint deshalb sinnvoll, dieses + BIOS gleich mit einem ausgewogenen Funktionsumfang auszustatten, welcher alle Funktionen + für das System bietet. Durch eine Bootoption kann dieses BIOS aber zur Laufzeit + ausgetauscht werden, um das Funktionssetup an konkrete Anforderungen anzupassen. + + Chip-Managment-Funktionen + - Bootfunktion für Administra + - Abfrage und Verwaltung des aktiven Soundsystems + - Abfrage Version und Spezifikation + + SD-Funktionen: + - FAT32 oder FAT16 + - Partitionen bis 1TB und Dateien bis 2GB + - Verzeichnisse + - Verwaltung aller Dateiattribute + - DIR-Marker System + - Verwaltung eines Systemordners + - Achtung: Keine Verwaltung von mehreren geöffneten Dateien! + + RTC-Funktionen: + - Datum, Uhrzeit auslesen + - Datum, Uhrzeit schreiben + - NVRAM auslesen + - NVRAM schreiben + - Wartefunktionen + + LAN-Funktionen: + - + +Komponenten : FATEngine 01/18/2009 Kwabena W. Agyeman MIT Lizenz + RTCEngine 11/22/2009 Kwabena W. Agyeman MIT Lizenz + PropTCP 12/08/2009 Harrison Pham MIT Lizenz + +COG's : MANAGMENT 1 COG + FAT/RTC 1 COG + NET 2 COGs + ------------------- + 4 COGs + +Logbuch : + +14-11-2008-dr235 - erste version erstellt +13-03-2009-dr235 - sd_eof eingefügt +25-01-2009-dr235 - komfortableres interface für hss-player eingefügt +19-03-2009-dr235 - seek, ftime, fattrib und fsize eingefügt +22-08-2009-dr235 - getcogs eingefügt +09-01-2010-dr235 - fehler in sfx_fire korrigiert +10-01-2010-dr235 - fehler in sdw_stop - hss wurde nicht wieder gestartet +15-03-2010-dr235 - start trios +21-03-2010-dr235 - screeninterface entfernt +24-03-2010-dr235 - start einbindung fatengine + - per flashcli laufen schon die ersten kommandos +25-03-2010-dr235 - umstellung fatengine auf fehlernummern +27-03-2010-dr235 - ich hab geburtstag :) + - test mount ok (fat16 + 32, div. sd-cards, fehlermeldungen) + - sd_volname eingefügt + test + - sd_checkmounted/sd_checkused/sd_checkfree eingefügt + test + - sd_checkopen eingefügt (test später) +28-03-2010-dr235 - fehler in der anbindung sd_open --> openFile: der modus + wurde als 0-term-string übergeben! änderung in einen normalen + 1-zeichen-parameter +02-04-2010-dr235 - sd_putblk/sd_getblk eingefügt und getestet +03-04-2010-dr235 - sd_opendit, sd_nextfile, sd_fattrib umgearbeitet und getestet +04-04-2010-dr235 - sd_newdir, sd_del, sd_rename eingefügt und getestet + - test sd_seek ok + - sd_chattrib, sd_chdir eingefügt und getestet + - mgr_getver, mgr_getspec, mgr_getcogs eingefügt + getestet + - mgr_aload eingefügt und getestet + - administra hat jetzt einen bootloader! :) +08-04-2010-dr235 - erster test dir-marker-system +12-04-2010-dr235 - neues soundsystem für wav eingebunden +16-04-2010-dr235 - komplexfehler im wav-system aufgelöst +21-04-2010-dr235 - pausen-modus positionsabfrage im wav-player eingefügt & getestet +29-04-2010-dr235 - wav-player: verwendung der dateigröße statt dem headerwert, da einige + programme definitiv den headerwert falsch setzen! +09-06-2010-dr085 - frida hat den fehler gefunden, welcher eine korrekte funktion der fatengine + nach einem bootvorgang von administra verhinderte :) +13-06-2010-dr235 - fehler in sd_volname korrigiert + - free/used auf fast umgestellt +18-06-2010-dr085 - fehler bei der businitialisierung: beim systemstart wurde ein kurzer impuls + auf der hs-leitung erzeugt, wodurch ein buszyklus verloren ging (symptom: + flashte man admin, so lief das system erst nach einem reset an) + - fatengine: endgültige beseitigung der feherhaften volname-abfrage +27-06-2010-dr085 - automount nach boot +19-07-2010-dr235 - booten eines alternativen administra-codes: befindet sich auf der karte + in der root eine datei "adm.sys", so wird diese datei automatisch in + administra geladen +18-09-2010-dr235 - funktion zur abfrage von eof eingefügt +29-10-2010-dr235 - grundlegende routinen für den plexbus eingefügt +03-12-2010-stepha - RTC Datums- und Zeit Funktionen +04-12-2010-stepha - NVRAM Funktionen +17-04-2013-dr235 - konstanten für administra-funktionen komplett ausgelagert + +Kommandoliste : + +Notizen : + + +}} + + +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 + + +' +---------- +' | +------- system +' | | +---- version (änderungen) +' | | | +- subversion (hinzufügungen) +CHIP_VER = $00_01_01_02 + +CHIP_SPEC = gc#A_FAT|gc#A_LDR|gc#A_COM|gc#A_LAN + +' +' hbeat --------+ +' clk -------+| +' /wr ------+|| +' /hs -----+||| +------------------------- /cs +' |||| |+------------------------ adm-p22 +' |||| ||+----------------------- adm-p21 (io) +' |||| |||+---------------------- adm-p20 (rx) +' |||| ||||+--------------------- adm-p19 (tx) +' |||| ||||| +------+ d0..d7 +' |||| ||||| | | +DB_IN = %00001001_00100000_00000000_00000000 'dira-wert für datenbuseingabe +DB_OUT = %00001001_00100000_00000000_11111111 'dira-wert für datenbusausgabe + +M1 = %00000010_00000000_00000000_00000000 'busclk=1? & /prop1=0? +M2 = %00000010_10000000_00000000_00000000 'maske: busclk & /cs (/prop1) + +M3 = %00000000_00000000_00000000_00000000 'busclk=0? +M4 = %00000010_00000000_00000000_00000000 'maske: busclk + +LED_OPEN = gc#HBEAT 'led-pin für anzeige "dateioperation" +SD_BASE = gc#A_SDD0 'baspin cardreader +CNT_HBEAT = 5_000_0000 'blinkgeschw. front-led + +MPLEN = 12000 'größe des hss-musikpuffers + +'index für dmarker +#0, RMARKER 'root + SMARKER 'system + UMARKER 'programmverzeichnis + AMARKER + BMARKER + CMARKER + +OBJ + sdfat : "adm-fat" 'fatengine + rtc : "adm-rtc" 'RTC-Engine + com : "adm-com" 'serielle schnittstelle + lan : "adm-lan" 'LAN + gc : "glob-con" 'globale konstanten + +VAR + + long dmarker[6] 'speicher für dir-marker + byte tbuf[20] 'stringpuffer + byte tbuf2[20] + long com_baud + +CON ''------------------------------------------------- ADMINISTRA + +PUB main | cmd,err 'chip: kommandointerpreter +''funktionsgruppe : chip +''funktion : kommandointerpreter +''eingabe : - +''ausgabe : - + + init_chip 'bus/vga/keyboard/maus initialisieren + repeat + cmd := bus_getchar 'kommandocode empfangen + err := 0 + case cmd + 0: !outa[LED_OPEN] 'led blinken + +' ---------------------------------------------- SD-FUNKTIONEN + gc#a_sdMount: sd_mount("M") 'sd-card mounten ' + gc#a_sdOpenDir: sd_opendir 'direktory öffnen + gc#a_sdNextFile: sd_nextfile 'verzeichniseintrag lesen + gc#a_sdOpen: sd_open 'datei öffnen + gc#a_sdClose: sd_close 'datei schließen + gc#a_sdGetC: sd_getc 'zeichen lesen + gc#a_sdPutC: sd_putc 'zeichen schreiben + gc#a_sdGetBlk: sd_getblk 'block lesen + gc#a_sdPutBlk: sd_putblk 'block schreiben + gc#a_sdSeek: sd_seek 'zeiger in datei positionieren + gc#a_sdFAttrib: sd_fattrib 'dateiattribute übergeben + gc#a_sdVolname: sd_volname 'volumelabel abfragen + gc#a_sdCheckMounted: sd_checkmounted 'test ob volume gemounted ist + gc#a_sdCheckOpen: sd_checkopen 'test ob eine datei geöffnet ist + gc#a_sdCheckUsed: sd_checkused 'test wie viele sektoren benutzt sind + gc#a_sdCheckFree: sd_checkfree 'test wie viele sektoren frei sind + gc#a_sdNewFile: sd_newfile 'neue datei erzeugen + gc#a_sdNewDir: sd_newdir 'neues verzeichnis wird erzeugt + gc#a_sdDel: sd_del 'verzeichnis oder datei löschen + gc#a_sdRename: sd_rename 'verzeichnis oder datei umbenennen + gc#a_sdChAttrib: sd_chattrib 'attribute ändern + gc#a_sdChDir: sd_chdir 'verzeichnis wechseln + gc#a_sdFormat: sd_format 'medium formatieren + gc#a_sdUnmount: sd_unmount 'medium abmelden + gc#a_sdDmAct: sd_dmact 'dir-marker aktivieren + gc#a_sdDmSet: sd_dmset 'dir-marker setzen + gc#a_sdDmGet: sd_dmget 'dir-marker status abfragen + gc#a_sdDmClr: sd_dmclr 'dir-marker löschen + gc#a_sdDmPut: sd_dmput 'dir-marker status setzen + gc#a_sdEOF: sd_eof 'eof abfragen + +' ---------------------------------------------- COM-FUNKTIONEN + gc#a_comInit: com_init + gc#a_comTx: com_tx + gc#a_comRx: com_rx + +' ---------------------------------------------- RTC-FUNKTIONEN + gc#a_rtcGetSeconds: rtc_getSeconds 'Returns the current second (0 - 59) from the real time clock. + gc#a_rtcGetMinutes: rtc_getMinutes 'Returns the current minute (0 - 59) from the real time clock. + gc#a_rtcGetHours: rtc_getHours 'Returns the current hour (0 - 23) from the real time clock. + gc#a_rtcGetDay: rtc_getDay 'Returns the current day (1 - 7) from the real time clock. + gc#a_rtcGetDate: rtc_getDate 'Returns the current date (1 - 31) from the real time clock. + gc#a_rtcGetMonth: rtc_getMonth 'Returns the current month (1 - 12) from the real time clock. + gc#a_rtcGetYear: rtc_getYear 'Returns the current year (2000 - 2099) from the real time clock. + gc#a_rtcSetSeconds: rtc_setSeconds 'Sets the current real time clock seconds. Seconds - Number to set the seconds to between 0 - 59. + gc#a_rtcSetMinutes: rtc_setMinutes 'Sets the current real time clock minutes. Minutes - Number to set the minutes to between 0 - 59. + gc#a_rtcSetHours: rtc_setHours 'Sets the current real time clock hours. Hours - Number to set the hours to between 0 - 23. + gc#a_rtcSetDay: rtc_setDay 'Sets the current real time clock day. Day - Number to set the day to between 1 - 7. + gc#a_rtcSetDate: rtc_setDate 'Sets the current real time clock date. Date - Number to set the date to between 1 - 31. + gc#a_rtcSetMonth: rtc_setMonth 'Sets the current real time clock month. Month - Number to set the month to between 1 - 12. + gc#a_rtcSetYear: rtc_setYear 'Sets the current real time clock year. Year - Number to set the year to between 2000 - 2099. + gc#a_rtcSetNVSRAM: rtc_setNVSRAM 'Sets the NVSRAM to the selected value (0 - 255) at the index (0 - 55). + gc#a_rtcGetNVSRAM: rtc_getNVSRAM 'Gets the selected NVSRAM value at the index (0 - 55). + gc#a_rtcPauseForSec: rtc_pauseForSeconds 'Pauses execution for a number of seconds. Returns a puesdo random value derived from the current clock frequency and the time when called. Number - Number of seconds to pause for between 0 and 2,147,483,647. + gc#a_rtcPauseForMSec: rtc_pauseForMilliseconds 'Pauses execution for a number of milliseconds. Returns a puesdo random value derived from the current clock frequency and the time when called. Number - Number of milliseconds to pause for between 0 and 2,147,483,647. + +' ---------------------------------------------- LAN-FUNKTIONEN + gc#a_lanStart: lan_start 'Start Network + gc#a_lanStop: lan_stop 'Stop Network + gc#a_lanFTPOpen: lan_ftpOpen 'FTP-Verbindung öffnen + gc#a_lanFTPClose: lan_ftpClose 'FTP-Verbindung schließen + gc#a_lanFTPNextFile: lan_ftpNextFile 'Verzeichniseintrag lesen + + +' ---------------------------------------------- CHIP-MANAGMENT + gc#a_mgrGetSpec: mgr_getspec 'spezifikation abfragen + gc#a_mgrALoad: mgr_aload 'neuen code booten + gc#a_mgrGetCogs: mgr_getcogs 'freie cogs abfragen + gc#a_mgrGetVer: mgr_getver 'codeversion abfragen + gc#a_mgrReboot: reboot 'neu starten + +' ---------------------------------------------- DEBUG-FUNKTIONEN + 255: mgr_debug 'debugfunktion + +PRI init_chip | err,i,j 'chip: initialisierung des administra-chips +''funktionsgruppe : chip +''funktion : - initialisierung des businterface +''eingabe : - +''ausgabe : - + + 'businterface initialisieren + outa[gc#bus_hs] := 1 'handshake inaktiv ,frida + dira := db_in 'datenbus auf eingabe schalten ,frida + + 'sd-card starten + clr_dmarker 'dir-marker löschen + sdfat.FATEngine + repeat + waitcnt(cnt + clkfreq/10) + until sd_mount("B") == 0 + 'err := sd_mount("B") + 'siglow(err) + + 'RTC initialisieren + rtc.setSQWOUTFrequency(3) 'RTC Uhrenquarzt Frequenz wählen + rtc.setSQWOUTState(0) 'RT Zähler ein + + 'adm-code booten? + ifnot \sdfat.openFile(string("adm.sys"), "R") 'test ob adm.sys vorhanden ist + \sdfat.bootPartition(string("adm.sys"), ".") 'neuen code booten + + 'serielle schnittstelle starten + com_baud := 115200 + com.start(gc#SER_RX,gc#SER_TX,0,com_baud) ' start the default serial interface + + 'Netz starten + lan.start + lan.ftpBoot + +PRI bus_putchar(zeichen) 'chip: ein byte über bus ausgeben +''funktionsgruppe : chip +''funktion : senderoutine für ein byte zu regnatix über den systembus +''eingabe : byte zeichen +''ausgabe : - + + waitpeq(M1,M2,0) 'busclk=1? & /prop1=0? + dira := db_out 'datenbus auf ausgabe stellen + outa[7..0] := zeichen 'daten ausgeben + outa[gc#bus_hs] := 0 'daten gültig + waitpeq(M3,M4,0) 'busclk=0? + outa[gc#bus_hs] := 1 'daten ungültig + dira := db_in 'bus freigeben + +PRI bus_getchar : zeichen 'chip: ein byte über bus empfangen +''funktionsgruppe : chip +''funktion : emfangsroutine für ein byte von regnatix über den systembus +''eingabe : - +''ausgabe : byte zeichen + + waitpeq(M1,M2,0) 'busclk=1? & /prop1=0? + zeichen := ina[7..0] 'daten einlesen + outa[gc#bus_hs] := 0 'daten quittieren + outa[gc#bus_hs] := 1 + waitpeq(M3,M4,0) 'busclk=0? + +PRI clr_dmarker| i 'chip: dmarker-tabelle löschen +''funktionsgruppe : chip +''funktion : dmarker-tabelle löschen +''eingabe : - +''ausgabe : - + + i := 0 + repeat 6 'alle dir-marker löschen + dmarker[i++] := TRUE + +CON ''------------------------------------------------- SUBPROTOKOLL-FUNKTIONEN + +PRI sub_getstr | i,len 'sub: string einlesen +''funktionsgruppe : sub +''funktion : subprotokoll um einen string von regnatix zu empfangen und im +'' : textpuffer (tbuf) zu speichern +''eingabe : - +''ausgabe : - +''busprotokoll : [get.len][get.byte(1)]..[get.byte(len)] +'' : len - länge des dateinamens + + repeat i from 0 to 19 'puffer löschen und kopieren + tbuf2[i] := tbuf[i] + tbuf[i] := 0 + len := bus_getchar 'längenbyte name empfangen + repeat i from 0 to len - 1 'dateiname einlesen + tbuf[i] := bus_getchar + +PRI sub_putstr(strptr)|len,i 'sub: string senden +''funktionsgruppe : sub +''funktion : subprotokoll um einen string an regnatix zu senden +''eingabe : strptr - zeiger auf einen string (0-term) +''ausgabe : - +''busprotokoll : [put.len][put.byte(1)]..[put.byte(len)] +'' : len - länge des dateinamens + + len := strsize(strptr) + bus_putchar(len) + repeat i from 0 to len - 1 'string übertragen + bus_putchar(byte[strptr][i]) + +PRI sub_putword(wert) 'sub: long senden +''funktionsgruppe : sub +''funktion : subprotokoll um einen 16bit-wert an regnatix zu senden +''eingabe : 16bit wert der gesendet werden soll +''ausgabe : - +''busprotokoll : [put.byte1][put.byte2] +'' : [ hsb ][ lsb ] + + bus_putchar(wert >> 8) + bus_putchar(wert) + +PRI sub_getword:wert 'sub: long empfangen +''funktionsgruppe : sub +''funktion : subprotokoll um einen 16bit-wert von regnatix zu empfangen +''eingabe : - +''ausgabe : 16bit-wert der empfangen wurde +''busprotokoll : [get.byte1][get.byte2] +'' : [ hsb ][ lsb ] + + wert := wert + bus_getchar << 8 + wert := wert + bus_getchar + +PRI sub_putlong(wert) 'sub: long senden +''funktionsgruppe : sub +''funktion : subprotokoll um einen long-wert an regnatix zu senden +''eingabe : 32bit wert der gesendet werden soll +''ausgabe : - +''busprotokoll : [put.byte1][put.byte2][put.byte3][put.byte4] +'' : [ hsb ][ ][ ][ lsb ] + + bus_putchar(wert >> 24) '32bit wert senden hsb/lsb + bus_putchar(wert >> 16) + bus_putchar(wert >> 8) + bus_putchar(wert) + +PRI sub_getlong:wert 'sub: long empfangen +''funktionsgruppe : sub +''funktion : subprotokoll um einen long-wert von regnatix zu empfangen +''eingabe : - +''ausgabe : 32bit-wert der empfangen wurde +''busprotokoll : [get.byte1][get.byte2][get.byte3][get.byte4] +'' : [ hsb ][ ][ ][ lsb ] + + wert := bus_getchar << 24 '32 bit empfangen hsb/lsb + wert := wert + bus_getchar << 16 + wert := wert + bus_getchar << 8 + wert := wert + bus_getchar + + +CON ''------------------------------------------------- CHIP-MANAGMENT-FUNKTIONEN + +PRI mgr_aload | err 'cmgr: neuen administra-code booten +''funktionsgruppe : cmgr +''funktion : administra mit neuem code booten +''eingabe : +''ausgabe : +''busprotokoll : [096][sub_getstr.fn] +'' : fn - dateiname des neuen administra-codes + sub_getstr + err := \sdfat.bootPartition(@tbuf, ".") + +PRI mgr_getcogs: cogs |i,c,cog[8] 'cmgr: abfragen wie viele cogs in benutzung sind +''funktionsgruppe : cmgr +''funktion : abfrage wie viele cogs in benutzung sind +''eingabe : - +''ausgabe : cogs - anzahl der cogs +''busprotokoll : [097][put.cogs] +'' : cogs - anzahl der belegten cogs + + cogs := i := 0 + repeat 'loads as many cogs as possible and stores their cog numbers + c := cog[i] := cognew(@entry, 0) + if c=>0 + i++ + while c => 0 + cogs := i + repeat 'unloads the cogs and updates the string + i-- + if i=>0 + cogstop(cog[i]) + while i=>0 + bus_putchar(cogs) + +PRI mgr_getver 'cmgr: abfrage der version +''funktionsgruppe : cmgr +''funktion : abfrage der version und spezifikation des chips +''eingabe : - +''ausgabe : cogs - anzahl der cogs +''busprotokoll : [098][sub_putlong.ver] +'' : ver - version +'' +---------- +'' | +------- system +'' | | +---- version (änderungen) +'' | | | +- subversion (hinzufügungen) +''version : $00_00_00_00 +'' + + sub_putlong(CHIP_VER) + +PRI mgr_getspec 'cmgr: abfrage der spezifikation des chips +''funktionsgruppe : cmgr +''funktion : abfrage der version und spezifikation des chips +''eingabe : - +''ausgabe : cogs - anzahl der cogs +''busprotokoll : [089][sub_putlong.spec] +'' : spec - spezifikation +'' +'' +---------- com +'' | +-------- i2c +'' | |+------- rtc +'' | ||+------ lan +'' | |||+----- sid +'' | ||||+---- wav +'' | |||||+--- hss +'' | ||||||+-- bootfähig +'' | |||||||+- dateisystem +''spezifikation : %00000000_00000000_00000000_01001111 + + sub_putlong(CHIP_SPEC) + +PRI mgr_debug 'cmgr: debug +' adresse der ersten variable senden + + sub_putlong(@dmarker) 'adresse erste variable als marker + +CON ''------------------------------------------------- SD-LAUFWERKS-FUNKTIONEN + +PRI sd_mount(mode) | err 'sdcard: sd-card mounten frida +''funktionsgruppe : sdcard +''funktion : eingelegtes volume mounten +''eingabe : - +''ausgabe : - +''busprotokoll : [001][put.error] +'' : error - fehlernummer entspr. list + + ifnot sdfat.checkPartitionMounted 'frida + err := \sdfat.mountPartition(0,0) 'karte mounten + 'bus_putchar(err) 'fehlerstatus senden + if mode == "M" 'frida + bus_putchar(err) 'fehlerstatus senden + + ifnot err + dmarker[RMARKER] := sdfat.getDirCluster 'root-marker setzen + + err := \sdfat.changeDirectory(string("system")) + ifnot err + dmarker[SMARKER] := sdfat.getDirCluster 'system-marker setzen + + sdfat.setDirCluster(dmarker[RMARKER]) 'root-marker wieder aktivieren + else 'frida + bus_putchar(0) 'frida + +PRI sd_opendir | err 'sdcard: verzeichnis öffnen +''funktionsgruppe : sdcard +''funktion : verzeichnis öffnen +''eingabe : - +''ausgabe : - +''busprotokoll : [002] + + err := \sdfat.listReset + +PRI sd_nextfile | strpt 'sdcard: nächsten eintrag aus verzeichnis holen +''funktionsgruppe : sdcard +''funktion : nächsten eintrag aus verzeichnis holen +''eingabe : - +''ausgabe : - +''busprotokoll : [003][put.status=0] +'' : [003][put.status=1][sub_putstr.fn] +'' : status - 1 = gültiger eintrag +'' : 0 = es folgt kein eintrag mehr +'' : fn - verzeichniseintrag string + + strpt := \sdfat.listName 'nächsten eintrag holen + if strpt 'status senden + bus_putchar(1) 'kein eintrag mehr + sub_putstr(strpt) + else + bus_putchar(0) 'gültiger eintrag folgt + +PRI sd_open | err,modus 'sdcard: datei öffnen +''funktionsgruppe : sdcard +''funktion : eine bestehende datei öffnen +''eingabe : - +''ausgabe : - +''busprotokoll : [004][get.modus][sub_getstr.fn][put.error] +'' : modus - "A" Append, "W" Write, "R" Read +'' : fn - name der datei +'' : error - fehlernummer entspr. list + + modus := bus_getchar 'modus empfangen + sub_getstr + err := \sdfat.openFile(@tbuf, modus) + bus_putchar(err) 'ergebnis der operation senden +'' outa[LED_OPEN] := 1 + +PRI sd_close | err 'sdcard: datei schließen +''funktionsgruppe : sdcard +''funktion : die aktuell geöffnete datei schließen +''eingabe : - +''ausgabe : - +''busprotokoll : [005][put.error] +'' : error - fehlernummer entspr. list + + err := \sdfat.closeFile + bus_putchar(err) 'ergebnis der operation senden +'' outa[LED_OPEN] := 0 + +PRI sd_getc | n 'sdcard: zeichen aus datei lesen +''funktionsgruppe : sdcard +''funktion : zeichen aus datei lesen +''eingabe : - +''ausgabe : - +''busprotokoll : [006][put.char] +'' : char - gelesenes zeichen + + n := \sdfat.readCharacter + bus_putchar(n) + +PRI sd_putc 'sdcard: zeichen in datei schreiben +''funktionsgruppe : sdcard +''funktion : zeichen in datei schreiben +''eingabe : - +''ausgabe : - +''busprotokoll : [007][get.char] +'' : char - zu schreibendes zeichen + + \sdfat.writeCharacter(bus_getchar) + + +PRI sd_eof 'sdcard: eof abfragen +''funktionsgruppe : sdcard +''funktion : eof abfragen +''eingabe : - +''ausgabe : - +''busprotokoll : [030][put.eof] +'' : eof - eof-flag + + bus_putchar(sdfat.getEOF) + +PRI sd_getblk 'sdcard: block aus datei lesen +''funktionsgruppe : sdcard +''funktion : block aus datei lesen +''eingabe : - +''ausgabe : - +''busprotokoll : [008][sub_getlong.count][put.char(1)]..[put.char(count)] +'' : count - anzahl der zu lesenden zeichen +'' : char - gelesenes zeichen + + repeat sub_getlong + bus_putchar(\sdfat.readCharacter) + + +PRI sd_putblk 'sdcard: block in datei schreiben +''funktionsgruppe : sdcard +''funktion : block in datei schreiben +''eingabe : - +''ausgabe : - +''busprotokoll : [009][sub_getlong.count][put.char(1)]..[put.char(count)] +'' : count - anzahl der zu schreibenden zeichen +'' : char - zu schreibende zeichen + + repeat sub_getlong + \sdfat.writeCharacter(bus_getchar) + +PRI sd_seek | wert 'sdcard: zeiger in datei positionieren +''funktionsgruppe : sdcard +''funktion : zeiger in datei positionieren +''eingabe : - +''ausgabe : - +''busprotokoll : [010][sub_getlong.pos] +'' : pos - neue zeichenposition in der datei + + wert := sub_getlong + \sdfat.setCharacterPosition(wert) + +PRI sd_fattrib | anr,wert 'sdcard: dateiattribute übergeben +''funktionsgruppe : sdcard +''funktion : dateiattribute abfragen +''eingabe : - +''ausgabe : - +''busprotokoll : [011][get.anr][sub_putlong.wert] +'' : anr - 0 = Dateigröße +'' : 1 = Erstellungsdatum - Tag +'' : 2 = Erstellungsdatum - Monat +'' : 3 = Erstellungsdatum - Jahr +'' : 4 = Erstellungsdatum - Sekunden +'' : 5 = Erstellungsdatum - Minuten +'' : 6 = Erstellungsdatum - Stunden +'' : 7 = Zugriffsdatum - Tag +'' : 8 = Zugriffsdatum - Monat +'' : 9 = Zugriffsdatum - Jahr +'' : 10 = Änderungsdatum - Tag +'' : 11 = Änderungsdatum - Monat +'' : 12 = Änderungsdatum - Jahr +'' : 13 = Änderungsdatum - Sekunden +'' : 14 = Änderungsdatum - Minuten +'' : 15 = Änderungsdatum - Stunden +'' : 16 = Read-Only-Bit +'' : 17 = Hidden-Bit +'' : 18 = System-Bit +'' : 19 = Direktory +'' : 20 = Archiv-Bit +'' : wert - wert des abgefragten attributes + + anr := bus_getchar + case anr + 0: wert := \sdfat.listSize + 1: wert := \sdfat.listCreationDay + 2: wert := \sdfat.listCreationMonth + 3: wert := \sdfat.listCreationYear + 4: wert := \sdfat.listCreationSeconds + 5: wert := \sdfat.listCreationMinutes + 6: wert := \sdfat.listCreationHours + 7: wert := \sdfat.listAccessDay + 8: wert := \sdfat.listAccessMonth + 9: wert := \sdfat.listAccessYear + 10: wert := \sdfat.listModificationDay + 11: wert := \sdfat.listModificationMonth + 12: wert := \sdfat.listModificationYear + 13: wert := \sdfat.listModificationSeconds + 14: wert := \sdfat.listModificationMinutes + 15: wert := \sdfat.listModificationHours + 16: wert := \sdfat.listIsReadOnly + 17: wert := \sdfat.listIsHidden + 18: wert := \sdfat.listIsSystem + 19: wert := \sdfat.listIsDirectory + 20: wert := \sdfat.listIsArchive + sub_putlong(wert) + +PRI sd_volname 'sdcard: volumenlabel abfragen +''funktionsgruppe : sdcard +''funktion : name des volumes überragen +''eingabe : - +''ausgabe : - +''busprotokoll : [012][sub_putstr.volname] +'' : volname - name des volumes +'' : len - länge des folgenden strings + + sub_putstr(\sdfat.listVolumeLabel) 'label holen und senden + +PRI sd_checkmounted 'sdcard: test ob volume gemounted ist +''funktionsgruppe : sdcard +''funktion : test ob volume gemounted ist +''eingabe : - +''ausgabe : - +''busprotokoll : [013][put.flag] +'' : flag - 0 = unmounted, 1 mounted + + bus_putchar(\sdfat.checkPartitionMounted) + +PRI sd_checkopen 'sdcard: test ob eine datei geöffnet ist +''funktionsgruppe : sdcard +''funktion : test ob eine datei geöffnet ist +''eingabe : - +''ausgabe : - +''busprotokoll : [014][put.flag] +'' : flag - 0 = not open, 1 open + + bus_putchar(\sdfat.checkFileOpen) + +PRI sd_checkused 'sdcard: anzahl der benutzten sektoren senden +''funktionsgruppe : sdcard +''funktion : anzahl der benutzten sektoren senden +''eingabe : - +''ausgabe : - +''busprotokoll : [015][sub_putlong.used] +'' : used - anzahl der benutzten sektoren + + sub_putlong(\sdfat.checkUsedSectorCount("F")) + +PRI sd_checkfree 'sdcard: anzahl der freien sektoren senden +''funktionsgruppe : sdcard +''funktion : anzahl der freien sektoren senden +''eingabe : - +''ausgabe : - +''busprotokoll : [016][sub_putlong.free] +'' : free - anzahl der freien sektoren + + sub_putlong(\sdfat.checkFreeSectorCount("F")) + +PRI sd_newfile | err 'sdcard: eine neue datei erzeugen +''funktionsgruppe : sdcard +''funktion : eine neue datei erzeugen +''eingabe : - +''ausgabe : - +''busprotokoll : [017][sub_getstr.fn][put.error] +'' : fn - name der datei +'' : error - fehlernummer entspr. liste + + sub_getstr + err := \sdfat.newFile(@tbuf) + bus_putchar(err) 'ergebnis der operation senden + +PRI sd_newdir | err 'sdcard: ein neues verzeichnis erzeugen +''funktionsgruppe : sdcard +''funktion : ein neues verzeichnis erzeugen +''eingabe : - +''ausgabe : - +''busprotokoll : [018][sub_getstr.fn][put.error] +'' : fn - name des verzeichnisses +'' : error - fehlernummer entspr. liste + + sub_getstr + err := \sdfat.newDirectory(@tbuf) + bus_putchar(err) 'ergebnis der operation senden + +PRI sd_del | err 'sdcard: eine datei oder ein verzeichnis löschen +''funktionsgruppe : sdcard +''funktion : eine datei oder ein verzeichnis löschen +''eingabe : - +''ausgabe : - +''busprotokoll : [019][sub_getstr.fn][put.error] +'' : fn - name des verzeichnisses oder der datei +'' : error - fehlernummer entspr. liste + + sub_getstr + err := \sdfat.deleteEntry(@tbuf) + bus_putchar(err) 'ergebnis der operation senden + +PRI sd_rename | err 'sdcard: datei oder verzeichnis umbenennen +''funktionsgruppe : sdcard +''funktion : datei oder verzeichnis umbenennen +''eingabe : - +''ausgabe : - +''busprotokoll : [020][sub_getstr.fn1][sub_getstr.fn2][put.error] +'' : fn1 - alter name +'' : fn2 - neuer name +'' : error - fehlernummer entspr. liste + + sub_getstr 'fn1 + sub_getstr 'fn2 + err := \sdfat.renameEntry(@tbuf2,@tbuf) + bus_putchar(err) 'ergebnis der operation senden + +PRI sd_chattrib | err 'sdcard: attribute ändern +''funktionsgruppe : sdcard +''funktion : attribute einer datei oder eines verzeichnisses ändern +''eingabe : - +''ausgabe : - +''busprotokoll : [021][sub_getstr.fn][sub_getstr.attrib][put.error] +'' : fn - dateiname +'' : attrib - string mit attributen +'' : error - fehlernummer entspr. liste + + sub_getstr + sub_getstr + err := \sdfat.changeAttributes(@tbuf2,@tbuf) + bus_putchar(err) 'ergebnis der operation senden + +PRI sd_chdir | err 'sdcard: verzeichnis wechseln +''funktionsgruppe : sdcard +''funktion : verzeichnis wechseln +''eingabe : - +''ausgabe : - +''busprotokoll : [022][sub_getstr.fn][put.error] +'' : fn - name des verzeichnisses +'' : error - fehlernummer entspr. list + sub_getstr + err := \sdfat.changeDirectory(@tbuf) + bus_putchar(err) 'ergebnis der operation senden + +PRI sd_format | err 'sdcard: medium formatieren +''funktionsgruppe : sdcard +''funktion : medium formatieren +''eingabe : - +''ausgabe : - +''busprotokoll : [023][sub_getstr.vlabel][put.error] +'' : vlabel - volumelabel +'' : error - fehlernummer entspr. list + + sub_getstr + err := \sdfat.formatPartition(0,@tbuf,0) + bus_putchar(err) 'ergebnis der operation senden + +PRI sd_unmount | err 'sdcard: medium abmelden +''funktionsgruppe : sdcard +''funktion : medium abmelden +''eingabe : - +''ausgabe : - +''busprotokoll : [024][put.error] +'' : error - fehlernummer entspr. list + + err := \sdfat.unmountPartition + bus_putchar(err) 'ergebnis der operation senden + ifnot err + clr_dmarker + +PRI sd_dmact|markernr 'sdcard: einen dir-marker aktivieren +''funktionsgruppe : sdcard +''funktion : ein ausgewählter dir-marker wird aktiviert +''eingabe : - +''ausgabe : - +''busprotokoll : [025][get.dmarker][put.error] +'' : dmarker - dir-marker +'' : error - fehlernummer entspr. list + markernr := bus_getchar + ifnot dmarker[markernr] == TRUE + sdfat.setDirCluster(dmarker[markernr]) + bus_putchar(sdfat#err_noError) + else + bus_putchar(sdfat#err_noError) + + +PRI sd_dmset|markernr 'sdcard: einen dir-marker setzen +''funktionsgruppe : sdcard +''funktion : ein ausgewählter dir-marker mit dem aktuellen verzeichnis setzen +''eingabe : - +''ausgabe : - +''busprotokoll : [026][get.dmarker] +'' : dmarker - dir-marker + + markernr := bus_getchar + dmarker[markernr] := sdfat.getDirCluster + +PRI sd_dmget|markernr 'sdcard: einen dir-marker abfragen +''funktionsgruppe : sdcard +''funktion : den status eines ausgewählter dir-marker abfragen +''eingabe : - +''ausgabe : - +''busprotokoll : [027][get.dmarker][sub_putlong.dmstatus] +'' : dmarker - dir-marker +'' : dmstatus - status des markers + + markernr := bus_getchar + sub_putlong(dmarker[markernr]) + +PRI sd_dmput|markernr 'sdcard: einen dir-marker übertragen +''funktionsgruppe : sdcard +''funktion : den status eines ausgewählter dir-marker übertragen +''eingabe : - +''ausgabe : - +''busprotokoll : [029][get.dmarker][sub_getlong.dmstatus] +'' : dmarker - dir-marker +'' : dmstatus - status des markers + + markernr := bus_getchar + dmarker[markernr] := sub_getlong + +PRI sd_dmclr|markernr 'sdcard: einen dir-marker löschen +''funktionsgruppe : sdcard +''funktion : ein ausgewählter dir-marker löschen +''eingabe : - +''ausgabe : - +''busprotokoll : [028][get.dmarker] +'' : dmarker - dir-marker + + markernr := bus_getchar + dmarker[markernr] := TRUE + +CON ''------------------------------------------------- COM-FUNKTIONEN + +PRI com_init 'com: serielle schnittstelle initialisieren +''funktionsgruppe : com +''funktion : serielle schnittstelle initialisieren +''eingabe : - +''ausgabe : - +''busprotokoll : [031][sub_getlong.baudrate] + + + com_baud := sub_getlong + com.start(gc#SER_RX,gc#SER_TX,0,com_baud) ' start the default serial interface + +PRI com_tx 'com: zeichen senden +''funktionsgruppe : com +''funktion : zeichen senden +''eingabe : - +''ausgabe : - +''busprotokoll : [032][get.char] + + com.tx(bus_getchar) + +PRI com_rx 'com: zeichen empfangen +''funktionsgruppe : com +''funktion : zeichen empfangen +''eingabe : - +''ausgabe : - +''busprotokoll : [033][put.char] + + bus_putchar(com.rx) + +CON ''------------------------------------------------- RTC-FUNKTIONEN + +PRI rtc_getSeconds 'rtc: Returns the current second (0 - 59) from the real time clock. +''funktionsgruppe : rtc +''busprotokoll : [041][sub_putlong.seconds] +'' : seconds - current second (0 - 59) + sub_putlong(rtc.getSeconds) + +PRI rtc_getMinutes 'rtc: Returns the current minute (0 - 59) from the real time clock. +''funktionsgruppe : rtc +''busprotokoll : [042][sub_putlong.minutes] +'' : minutes - current minute (0 - 59) + sub_putlong(rtc.getMinutes) + +PRI rtc_getHours 'rtc: Returns the current hour (0 - 23) from the real time clock. +''funktionsgruppe : rtc +''busprotokoll : [043][sub_putlong.hours] +'' : hours - current hour (0 - 23) + sub_putlong(rtc.getHours) + +PRI rtc_getDay 'rtc: Returns the current day of the week (1 - 7) from the real time clock. +''funktionsgruppe : rtc +''busprotokoll : [044][sub_putlong.day] +'' : day - current day (1 - 7) of the week + sub_putlong(rtc.getDay) + +PRI rtc_getDate 'rtc: Returns the current date (1 - 31) from the real time clock. +''funktionsgruppe : rtc +''busprotokoll : [045][sub_putlong.date] +'' : date - current date (1 - 31) of the month + sub_putlong(rtc.getDate) + +PRI rtc_getMonth 'rtc: Returns the current month (1 - 12) from the real time clock. +''funktionsgruppe : rtc +''busprotokoll : [046][sub_putlong.month] +'' : month - current month (1 - 12) + sub_putlong(rtc.getMonth) + +PRI rtc_getYear 'rtc: Returns the current year (2000 - 2099) from the real time clock. +''funktionsgruppe : rtc +''busprotokoll : [047][sub_putlong.year] +'' : year - current year (2000 - 2099) + sub_putlong(rtc.getYear) + +PRI rtc_setSeconds : seconds 'rtc: Sets the current real time clock seconds. +''funktionsgruppe : rtc +''busprotokoll : [048][sub_getlong.seconds] +'' : seconds - Number to set the seconds to between 0 - 59. + rtc.setSeconds(sub_getlong) + +PRI rtc_setMinutes : minutes 'rtc: Sets the current real time clock minutes. +''funktionsgruppe : rtc +''busprotokoll : [049][sub_getlong.minutes] +'' : minutes - Number to set the minutes to between 0 - 59. + rtc.setMinutes(sub_getlong) + +PRI rtc_setHours 'rtc: Sets the current real time clock hours. +''funktionsgruppe : rtc +''busprotokoll : [050][sub_getlong.hours] +'' : hours - Number to set the hours to between 0 - 23.51: + rtc.setHours(sub_getlong) + +PRI rtc_setDay 'rtc: Sets the current real time clock day. +''funktionsgruppe : rtc +''busprotokoll : [051][sub_getlong.day] +'' : day - Number to set the day to between 1 - 7. + rtc.setDay(sub_getlong) + +PRI rtc_setDate 'rtc: Sets the current real time clock date. +''funktionsgruppe : rtc +''busprotokoll : [052][sub_getlong.date] +'' : date - Number to set the date to between 1 - 31. + rtc.setDate(sub_getlong) + +PRI rtc_setMonth 'rtc: Sets the current real time clock month. +''funktionsgruppe : rtc +''busprotokoll : [053][sub_getlong.month] +'' : month - Number to set the month to between 1 - 12. + rtc.setMonth(sub_getlong) + +PRI rtc_setYear 'rtc: Sets the current real time clock year. +''funktionsgruppe : rtc +''busprotokoll : [054][sub_getlong.year] +'' : year - Number to set the year to between 2000 - 2099. + rtc.setYear(sub_getlong) + +PRI rtc_setNVSRAM | index, value 'rtc: Sets the NVSRAM to the selected value (0 - 255) at the index (0 - 55). +''funktionsgruppe : rtc +''busprotokoll : [055][sub_getlong.index][sub_getlong.value] +'' : index - The location in NVRAM to set (0 - 55). │ +'' : value - The value (0 - 255) to change the location to. │ + index := sub_getlong + value := sub_getlong + rtc.setNVSRAM(index, value) + +PRI rtc_getNVSRAM 'rtc: Gets the selected NVSRAM value at the index (0 - 55). +''funktionsgruppe : rtc +''busprotokoll : [056][sub_getlong.index][sub_getlong.value] +'' : index - The location in NVRAM to get (0 - 55). │ + sub_putlong(rtc.getNVSRAM(sub_getlong)) + +PRI rtc_pauseForSeconds 'rtc: Pauses execution for a number of seconds. +''funktionsgruppe : rtc +''busprotokoll : [057][sub_getlong.number][sub_putlong.number] +'' : Number - Number of seconds to pause for between 0 and 2,147,483,647. +'' : Returns a puesdo random value derived from the current clock frequency and the time when called. + + sub_putlong(rtc.pauseForSeconds(sub_getlong)) + +PRI rtc_pauseForMilliseconds 'rtc: Pauses execution for a number of milliseconds. +''funktionsgruppe : rtc +''busprotokoll : [058][sub_getlong.number][sub_putlong.number] +'' : Number - Number of milliseconds to pause for between 0 and 2,147,483,647. +'' : Returns a puesdo random value derived from the current clock frequency and the time when called. + sub_putlong(rtc.pauseForMilliseconds(sub_getlong)) + +CON ''------------------------------------------------- NET-FUNKTIONEN + +PRI lan_start + + lan.start + +PRI lan_stop + + lan.stop + +PRI lan_ftpOpen | addr + + addr := sub_getlong + lan.ftpOpen(addr) + +PRI lan_ftpClose + + lan.ftpClose + +PRI lan_ftpNextFile | strpt 'ftp: nächsten eintrag aus verzeichnis holen +''funktionsgruppe : lan - ftp +''funktion : nächsten eintrag aus verzeichnis holen +''eingabe : - +''ausgabe : - +''busprotokoll : [003][put.status=0] +'' : [003][put.status=1][sub_putstr.fn] +'' : status - 1 = gültiger eintrag +'' : 0 = es folgt kein eintrag mehr +'' : fn - verzeichniseintrag string + + strpt := \lan.ftpListName 'nächsten eintrag holen + if strpt 'status senden + bus_putchar(1) 'kein eintrag mehr + sub_putstr(strpt) + else + bus_putchar(0) 'gültiger eintrag folgt + +DAT 'dummyroutine für getcogs + org +' +' Entry: dummy-assemblercode fuer cogtest +' +entry jmp entry 'just loops + + + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, PRIlish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}} + diff --git a/system/regnatix/ipconfig.spin b/system/regnatix/ipconfig.spin new file mode 100644 index 0000000..6676521 --- /dev/null +++ b/system/regnatix/ipconfig.spin @@ -0,0 +1,173 @@ +{{ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Autor: Jörg Deckert │ +│ Copyright (c) 2013 Jörg Deckert │ +│ See end of file for terms of use. │ +│ Die Nutzungsbedingungen befinden sich am Ende der Datei │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +Informationen : hive-project.de +Kontakt : joergd@bitquell.de +System : TriOS +Name : flash +Chip : Regnatix +Typ : Programm +Version : +Subversion : +Funktion : IP-Konfiguration in NVRAM ablegen +Komponenten : - +COG's : - +Logbuch : + +11.06.2013-joergd - erste Version, basierend auf time.spin + + +Kommandoliste : + + +Notizen : + + +}} + +OBJ + ios: "reg-ios" + str: "glob-string" + num: "glob-numbers" 'Number Engine + +CON + +_CLKMODE = XTAL1 + PLL16X +_XINFREQ = 5_000_000 + +CON 'NVRAM Konstanten -------------------------------------------------------------------------- + +#4, NVRAM_IPADDR +#8, NVRAM_IPMASK +#12, NVRAM_IPGW +#16, NVRAM_IPDNS +#20, NVRAM_IPBOOT +#24, NVRAM_HIVE ' 4 Bytes + +VAR + +byte parastr[64] + +PUB main + + ios.start 'ios initialisieren + ios.printnl + ios.parastart 'parameterübergabe starten + repeat while ios.paranext(@parastr) 'parameter einlesen + if byte[@parastr][0] == "/" 'option? + case byte[@parastr][1] + "?": ios.print(@help) + "l": cmd_listcfg + "a": if ios.paranext(@parastr) + cmd_setaddr(NVRAM_IPADDR, @parastr) + "m": if ios.paranext(@parastr) + cmd_setaddr(NVRAM_IPMASK, @parastr) + "g": if ios.paranext(@parastr) + cmd_setaddr(NVRAM_IPGW, @parastr) + "d": if ios.paranext(@parastr) + cmd_setaddr(NVRAM_IPDNS, @parastr) + "b": if ios.paranext(@parastr) + cmd_setaddr(NVRAM_IPBOOT, @parastr) + "i": if ios.paranext(@parastr) + cmd_sethive(num.FromStr(@parastr, num#DEC)) + other: ios.print(@help) + ios.stop + +PRI cmd_listcfg | hiveid 'nvram: IP-Konfiguration anzeigen + + ios.print(string(" IP-Adresse: ")) + listaddr(NVRAM_IPADDR) + ios.print(string("/")) + listaddr(NVRAM_IPMASK) + ios.printnl + + ios.print(string(" Gateway: ")) + listaddr(NVRAM_IPGW) + ios.printnl + + ios.print(string(" DNS-Server: ")) + listaddr(NVRAM_IPDNS) + ios.printnl + + ios.print(string(" Boot-Server: ")) + listaddr(NVRAM_IPBOOT) + ios.printnl + + ios.print(string(" Hive-Id: ")) + hiveid := ios.getNVSRAM(NVRAM_HIVE) + hiveid := hiveid + ios.getNVSRAM(NVRAM_HIVE+1) << 8 + hiveid := hiveid + ios.getNVSRAM(NVRAM_HIVE+2) << 16 + hiveid := hiveid + ios.getNVSRAM(NVRAM_HIVE+3) << 24 + ios.print(str.trimCharacters(num.ToStr(hiveid, num#DEC))) + ios.printnl + +PRI listaddr (nvidx) | count 'nvram: IP-Adresse setzen + + repeat count from 0 to 3 + if(count) + ios.print(string(".")) + ios.print(str.trimCharacters(num.ToStr(ios.getNVSRAM(nvidx+count), num#DEC))) + +PRI cmd_setaddr (nvidx, ipaddr) | pos, count 'nvram: IP-Adresse setzen + + count := 0 + repeat while ipaddr + pos := str.findCharacter(ipaddr, ".") + if(pos) + byte[pos++] := 0 + ios.setNVSRAM(nvidx+count++, num.FromStr(ipaddr, num#DEC)) + ipaddr := pos + if(count == 4) + quit + + ios.lanstart + cmd_listcfg + +PRI cmd_sethive (hiveid) 'nvram: IP-Adresse setzen + + ios.setNVSRAM(NVRAM_HIVE, hiveid & $FF) + ios.setNVSRAM(NVRAM_HIVE+1, (hiveid >> 8) & $FF) + ios.setNVSRAM(NVRAM_HIVE+2, (hiveid >> 16) & $FF) + ios.setNVSRAM(NVRAM_HIVE+3, (hiveid >> 24) & $FF) + + ios.lanstart + cmd_listcfg + +DAT 'sys: helptext + + +help byte "/? : Hilfe",13 + byte "/l : Konfiguration anzeigen",13 + byte "/a : IP-Adresse setzen",13 + byte "/m : Netzwerk-Maske setzen",13 + byte "/g : Gateway setzen",13 + byte "/d : DNS-Server setzen",13 + byte "/b : Boot-Server setzen",13 + byte "/i : Hive-Id setzen",13 + byte 0 + +DAT 'lizenz + +{{ + +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ TERMS OF USE: MIT License │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ +│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ +│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ +│is furnished to do so, subject to the following conditions: │ +│ │ +│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ +│ │ +│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ +│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ +│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +}}