'**************************************************************** '* Name : HTTP_1.PBP * '* Author : Henrik Olsson * '* Notice : Copyright (c) 2011 Henrik Olsson 2010 * '* : All Rights Reserved * '* Date : 2011-05-31 * '* Version : 1.0 * '* Notes : * '* : * '**************************************************************** DEFINE OSC 64 ' Default oscillator speed on the AMICUS18 is 16*4MHz DEFINE LOADER_USED 1 ' We're using a bootloader. DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1 DEFINE HSER_CLROERR 1 ' Clear overflow automatically DEFINE HSER_SPBRG 138 ' 115200 Baud @ 64MHz, -0,08% SPBRGH = 0 BAUDCON.3 = 1 ' Enable 16 bit baudrate generator TRISC = %10010111 ' RX, TX, MOSI, MISO, SCK, N/U, N/U, N/U TRISB = %11011011 ' N/U, N/U, W5100_CS, N/U, N/U, SD_CS, N/U, W5100_Interrupt ' Aliases for the MSSP module status and control bits. SSPEN VAR SSPCON1.5 ' SSP Enable bit CKP VAR SSPCON1.4 ' Clock Polarity Select SMP VAR SSPSTAT.7 ' Data input sample phase CKE VAR SSPSTAT.6 ' Clock Edge Select bit SSPIF VAR PIR1.3 ' SPI interrupt flag ' Set up the MSSP module. CKP = 0 ' Clock idles low CKE = 1 ' Transmit on active to idle transition. SSPIF = 0 ' Clear buffer full status SMP = 0 ' Sample in middle of data SSPEN = 1 ' Enable SPI pins SSPCON1.0 = 1 ' Slow down SPI clock to Fosc/16 for now. ' Alias and logic level for the Chip Select line to the W5100 W5100_Select VAR PortB.5 ' Chip select line of W5100 connected to RB.5 W5100_Select = 1 INCLUDE "W5100_defs.pbp" ' Register definitions and constants for the W5100. WizResponse VAR BYTE[4] WizPtr VAR WORD ' Raw pointer value to the socket memory area. WizData VAR WORD ' Databyte to and from the W5100. WizAdress VAR WORD ' Adress to access in the W5100. WizStart VAR WORD ' Physical start adress of data in the socket memory area. WizEnd VAR WORD ' Physical end adress of data in the socket memory area. WizSize VAR WORD ' Number of bytes in the socket memory area. Counter VAR WORD ' Just a temporary debug-aid-counter. HSEROUT ["Program start",13] GOSUB Init_W5100 GOSUB Init_Socket_0 Main: ' The socket 0 mode register automatically switches to SOCK_ESTABLISHED ' when a valid request to connect comes in from a client. WizAdress = W5100_S0_SR : GOSUB Read_W5100 If WizData = W5100_SOCK_ESTABLISHED then Gosub CheckBufferForData If WizSize > 0 then GOSUB GetData ENDIF Pause 500 Goto Main '****************************************************************************************** ' Subroutine to initialize the W5100 controller. ' This is done by setting bit7 in the W5100's mode register. ' The controller is initialized and the bit is automatically cleared byt the hardware. ' Then we set the MAC adress, IP adress, Netmask and Gateway adress. These are hardcoded ' for now but can/should be changed to variables or EEPROM stored values later. '****************************************************************************************** Init_W5100: 'Perform a soft reset of the W5100 WizAdress = W5100_Mode : WizData = 128 : Gosub Write_W5100 ' Set W5100 MAC adress WizAdress = W5100_SHAR0 : WizData = $90 : GOSUB Write_W5100 WizAdress = W5100_SHAR1 : WizData = $A2 : GOSUB Write_W5100 WizAdress = W5100_SHAR2 : WizData = $DA : GOSUB Write_W5100 WizAdress = W5100_SHAR3 : WizData = $00 : GOSUB Write_W5100 WizAdress = W5100_SHAR4 : WizData = $48 : GOSUB Write_W5100 WizAdress = W5100_SHAR5 : WizData = $03 : GOSUB Write_W5100 ' Set W5100 IP adress WizAdress = W5100_SIPR0 : WizData = 192 : Gosub Write_W5100 WizAdress = W5100_SIPR1 : WizData = 168 : Gosub Write_W5100 WizAdress = W5100_SIPR2 : WizData = 1 : Gosub Write_W5100 WizAdress = W5100_SIPR3 : WizData = 50 : Gosub Write_W5100 ' Set W5100 Net mask WizAdress = W5100_SUBR0 : WizData = 255 : GOSUB Write_W5100 WizAdress = W5100_SUBR1 : WizData = 255 : GOSUB Write_W5100 WizAdress = W5100_SUBR2 : WizData = 255 : GOSUB Write_W5100 WizAdress = W5100_SUBR3 : WizData = 0 : GOSUB Write_W5100 ' Set W5100 gateway adress WizAdress = W5100_GAR0 : WizData = 192 : GOSUB Write_W5100 WizAdress = W5100_GAR1 : WizData = 168 : GOSUB Write_W5100 WizAdress = W5100_GAR2 : WizData = 1 : GOSUB Write_W5100 WizAdress = W5100_GAR3 : WizData = 254 : GOSUB Write_W5100 RETURN '****************************************************************************************** '****************************************************************************************** '****************************************************************************************** ' Subroutine to initialize socket 0 of the W5100 controller. '****************************************************************************************** Init_Socket_0: ' Set socket 0 protocol to TCP by assigning the sockets mode register the value 1. WizAdress=W5100_S0_MR : WizData = 1 : GOSUB Write_W5100 ' Set the port register of socket 0. WizAdress=W5100_S0_PORT0 : WizData = 0 : Gosub Write_W5100 WizAdress=W5100_S0_PORT1 : WizData = 80 : GOSUB Write_W5100 Open_Socket_0: ' Set the Command Register of socket 0 to OPEN - this inits the socket. WizAdress = W5100_S0_CR : WizData = W5100_Sn_OPEN : GOSUB Write_W5100 ' Now switch Socket 0 into Listen Mode. WizAdress = W5100_S0_CR : WizData = W5100_Sn_LISTEN : GOSUB Write_W5100 RETURN '****************************************************************************************** '****************************************************************************************** ' Subroutine to check socket 0 receive memory buffer for data. ' ' We're not actually reading the data, we are determining if data is available by checking ' the byte count of the RX-buffer in the sockets memory area. ' ' An alternative method is to check the RECV bit in the sockets interrupt register but and/or ' use the hardware interrupt signal but that is not the way we are currently handling it. ' ' If data is available we set the variable WizSize to the value corresponding to the number ' of bytes available in the receive buffer. If that value is larger than zero ' (ie data IS available) we also calculate the physical adress of the first and last ' available byte byte. These values are stored in the variables WizStart and WizEnd respectively. ' ' Note: Because the sockets RX buffer in the W5100 is circular WizEnd might be less than WizStart. ' This needs to be treated properly in the routine that is reading the data from the buffer. '****************************************************************************************** CheckBufferForData: ' Read the sockets receive size register. WizAdress = W5100_S0_RX_RSR0 : GOSUB Read_W5100 : WizSize.HighByte = WizData WizAdress = W5100_S0_RX_RSR1 : GOSUB Read_W5100 : WizSize.LowByte = WizData ' If received size is more than 0 we do indeed have new data in the buffer. ' In that case we read the socket 0 receive pointer register. If WizSize > 0 then WizAdress = W5100_S0_RX_RD0 : Gosub Read_W5100 : WizPtr.HighByte = WizData WizAdress = W5100_S0_RX_RD1 : GOSUB Read_W5100 : WizPtr.LowByte = WizData ' Then we calculate the physical adress of the first "fresh" byte in the buffer. ' W5100_S0_RX_START, W5100_S0_RX_END and W5100_S0_RX_MASK are constants defined in the ' W5100_defs.pbp file. These holds the start-adress, end-adress and the mask value needed ' to calculate the physical adress based on the sockets RX pointer. ' Actual adress of first byte. WizStart = W5100_S0_RX_START + (WizPtr & W5100_S0_RX_MASK) ' Is the buffer about to wrap around? If WizStart + WizSize > W5100_S0_RX_END then WizEnd = W5100_S0_RX_START + ((WizStart + WizSize) - W5100_S0_RX_END) WizEnd = WizEnd - 2 ' Account for the "zero indexing" ELSE WizEnd = WizStart + WizSize - 1 ' No wrap around. Endif ENDIF RETURN '****************************************************************************************** ' Subroutine to read one register from the W5100. ' Prior to calling this routine the variable WizAdress should be loaded with the adress ' that should be read. The data at that adress is read and placed in the variable WizData ' before execution is returned to the caller. The array WizResponse is loaded with the data ' that is being shifted in from the W5100, this should be 0, 1, 2, data for a successful ' read operation. WizResponse could be used to check for successfull operation by checking ' that the first three bytes are indeed 0, 1 and 2. '****************************************************************************************** Read_W5100: WizResponse[0] = SSPBUF ' Dummy read W5100_Select = 0 ' Select W5100 SSPBUF = W5100_READ_OP ' Send OP code for read operation While SSPSTAT.0 = 0 : WEND ' Wait for operation to complete WizResponse[0] = SSPBUF ' Store result, should be 0 SSPBUF = WizAdress.HighByte ' Send high byte of adress While SSPSTAT.0 = 0 : WEND ' Wait for operation to complete WizResponse[1] = SSPBUF ' Store result, should be 1 SSPBUF = WizAdress.LowByte ' Send low byte of adress While SSPSTAT.0 = 0 : WEND ' Wait for operation to complete WizResponse[2] = SSPBUF ' Store result, should be 2 SSPBUF = 0 ' Send data While SSPSTAT.0 = 0 : WEND ' Wait for operation to completeD WizResponse[3] = SSPBUF ' Store result, will be the actual data read at the specified adress WizData = WizResponse[3] ' Copy databyte from array to WizData. W5100_Select = 1 ' Deselect the W5100 RETURN '****************************************************************************************** '****************************************************************************************** '****************************************************************************************** ' Subroutine for writing a single value to a register in the W5100. ' Prior to calling this routine the variable WizAdress must be loaded with the adress ' to which the data should be written and the actual data value should be placed ' in the variable WizData. ' ' The array WizResponse is loaded with the data being shifted in ' from the W5100, these bytes should always read 0, 1, 2, 3 for a successful write operation. ' WizResponse could be used to check for successful write operation by checking that ' the bytes are indeed 0, 1, 2 and 3 but it is not implemented in this subroutine. '****************************************************************************************** Write_W5100: WizResponse[0] = SSPBUF ' Dummy read. W5100_Select = 0 ' Pull chip select line low to select W5100 SSPBUF = W5100_WRITE_OP ' Send OP code for write operation While SSPSTAT.0 = 0 : WEND ' Wait for operation to complete WizResponse[0] = SSPBUF ' Store result, should be 0 SSPBUF = WizAdress.HighByte ' Send high byte of adress While SSPSTAT.0 = 0 : WEND ' Wait for operation to complete WizResponse[1] = SSPBUF ' Store result, should be 1 SSPBUF = WizAdress.LowByte ' Send low byte of adress While SSPSTAT.0 = 0 : WEND ' Wait for operation to complete WizResponse[2] = SSPBUF ' Store result, should be 2 SSPBUF = WizData ' Send the data byte While SSPSTAT.0 = 0 : WEND ' Wait for operation to complete WizResponse[3] = SSPBUF ' Store the result, should be 3 W5100_Select = 1 ' Deselect the W5100 RETURN '****************************************************************************************** '****************************************************************************************** '***************************************************************************************************** GetData: HSEROUT [REP "-"\20, " Data read from Rx buffer follows ", REP "-"\20, 13] Counter = 0 ' Temporary as a dubug aid ' Do we have a buffer wrap around condition? If WizEnd < WizStart THEN ' When that happends we need to start reading at the first byte in the received ' package and go on until the end of the sockets RX memory.... For WizAdress = WizStart to W5100_S0_RX_END Gosub Read_W5100 HSEROUT[WizData] Counter = Counter + 1 ' Keep count NEXT ' ...then we need to start over at the beginning of the buffer and keep reading ' until we've got all the bytes in the buffer. For WizAdress = W5100_S0_RX_START to WizEnd Gosub Read_W5100 HSEROUT[WizData] Counter = Counter + 1 ' Keep count Next ELSE ' There's no buffer wrap-around. ' WizStart now contains the physical adress of the first byte to read. For WizAdress = WizStart to WizEnd Gosub Read_W5100 HSEROUT[WizData] Counter = Counter + 1 ' Keep count NEXT ENDIF HSEROUT [REP "-"\23, " End of data from Rx buffer ", REP "-"\23, 13] HSEROUT ["Total number of bytes read:", #Counter,13] HSEROUT [REP "-"\76, 13, 13] ' The variable RxPtr contains the "raw value" read from the sockets Rx Read Pointer Register. ' Now we need to be update that so it points one "step" ahead of the last location we just read. ' This is done to let the W5100 how "far" in the buffer we've read and that it can use any space ' "before" this location for new data. Note that this is not the ACTUAL adress of the data, ' just the unmasked index. WizPtr = WizPtr + WizSize WizAdress = W5100_S0_RX_RD0 : WizData = WizPtr.HighByte : GOSUB Write_W5100 WizAdress = W5100_S0_RX_RD1 : WizData = WizPtr.LowByte : GOSUB Write_W5100 ' Then we send the RECV command to the sockets command register to let it know that ' we've handled all the data we currently are prepared to handle. This updates the ' pointers in the sockets memory so that it knows where to put new data. It is not ' until after issuing the RECV command that the sockets RX pointer is actually updated ' even though we write to it above. WizAdress = W5100_S0_CR : WizData = W5100_Sn_RECV : GOSUB Write_W5100 WizAdress = W5100_S0_CR : WizData = W5100_Sn_LISTEN : GOSUB Write_W5100 RETURN '*****************************************************************************************************