URL
https://opencores.org/ocsvn/utosnet/utosnet/trunk
Subversion Repositories utosnet
Compare Revisions
- This comparison shows the changes necessary to convert path
/utosnet
- from Rev 6 to Rev 7
- ↔ Reverse comparison
Rev 6 → Rev 7
/trunk/software/Digi_app/root.cxx
0,0 → 1,608
/* |
* uTosNet_spi Digi application |
|
* root.cxx |
* File created by: |
* Simon Falsig |
* University of Southern Denmark |
* Copyright 2010 |
* |
* This program is free software: you can redistribute it and/or modify |
* it under the terms of the GNU Lesser General Public License as published by |
* the Free Software Foundation, either version 3 of the License, or |
* (at your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU Lesser General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public License |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <tx_api.h> |
#include <sockapi.h> |
#include <pthread.h> |
#include <netoserr.h> |
#include <string> |
#include <appservices.h> |
#include <wxroot.h> |
|
#include "spi_master_api.h" |
#include "gpiomux_def.h" |
#include "appconf.h" |
#include "iam.hh" |
#include "Npttypes.h" |
#include "cliapi.h" //Needed for custom cli functions |
|
|
#define APP_SPI_MASTER_GPIO_CS 0 |
#define APP_SPI_MASTER_GPIO_CLK 5 |
#define APP_SPI_MASTER_GPIO_RXD 3 |
#define APP_SPI_MASTER_GPIO_TXD 7 |
|
|
#define MAX_CONNECTIONS 16 //The maximum number of simultaneous connections, may be adjusted |
#define PACKETSIZE 8 //Do not change |
|
#define DO_COMMIT_READ_PRE (1<<28) |
#define DO_READ (1<<27) |
#define DO_COMMIT_READ_POST (1<<26) |
#define DO_COMMIT_WRITE_PRE (1<<12) |
#define DO_WRITE (1<<11) |
#define DO_COMMIT_WRITE_POST (1<<10) |
|
enum THREAD_STATUS_TYPES |
{ |
FREE, |
RUNNING, |
TERMINATED |
}; |
|
struct sockAddrIn |
{ |
short sin_family; // address family |
unsigned short sin_port; // port |
struct in_addr sin_addr; // ip address |
char sin_zero[8]; |
|
/* |
* Adding constructors to sockaddr_in structure |
*/ |
sockAddrIn(){sin_family = AF_INET;} |
|
sockAddrIn(unsigned short port,unsigned long addr = 0) |
{ |
sin_family = AF_INET; |
sin_port = port; |
sin_addr.s_addr = addr; |
}; |
}; |
|
|
THREAD_STATUS_TYPES threadInUse[MAX_CONNECTIONS]; |
SOCKET clientSockets[MAX_CONNECTIONS]; |
sockAddrIn* clientSockaddrs[MAX_CONNECTIONS]; |
|
/* |
* Server thread function |
*/ |
void netServer(unsigned long port); |
|
|
/* |
* Network Read thread function |
*/ |
void netRead(unsigned long threadIndex); |
|
|
/* |
* FPGA Write thread function |
*/ |
void fpgaWrite(unsigned long comHandle); |
|
|
int readDebug(int fd, int n, char * args[]); //Custom cli functions |
int readDebugHelp(int fd, int n, char * args[]); // |
|
/* |
* Set this to 1 to run the system POST tests during startup. |
*/ |
const int APP_POST = 0; |
|
/* |
* Set this to 1 to run the manufacturing burn in tests. |
*/ |
int APP_BURN_IN_TEST = 0; |
|
/* |
* Thread size |
*/ |
#define STACK_SIZE 4096 |
|
/* |
* Thread control blocks |
*/ |
TX_THREAD net_server; |
TX_THREAD fpga_write; |
TX_THREAD *net_read[MAX_CONNECTIONS]; |
|
/* |
* Message queues |
*/ |
TX_QUEUE inMsg; |
|
/* |
* Global variables |
*/ |
unsigned int currentReceiverIndex = MAX_CONNECTIONS; |
char* currentReceiverData; |
int debug[2]; |
|
|
|
/* |
* |
* Function: void applicationTcpDown (void) |
* |
* Description: |
* |
* This routine will be called by the NET+OS root thread once every |
* clock tick while it is waiting for the TCP/IP stack to come up. |
* |
* This routone is called to print the application name and then |
* to print the '.' every second. |
* |
* This function will not be called once the stack has started. |
* |
* This function uses the global C++ object PrintApplicationDown app_down. |
* |
* Parameters: |
* |
* none |
* |
* Return Values: |
* |
* none |
* |
*/ |
extern "C" |
void applicationTcpDown (void) |
{ |
} |
|
|
|
/* |
* |
* Function: void applicationStart (void) |
* |
* Description: |
* |
* This routine is responsible for starting the user application. It should |
* create any threads or other resources the application needs. |
* |
* ThreadX, the NET+OS device drivers, and the TCP/IP stack will be running |
* when this function is called. |
* |
* This function uses global C++ object: |
* PrintApplicationDown app_down. |
* |
* Parameters: |
* |
* none |
* |
* Return Values: |
* |
* none |
* |
*/ |
|
extern "C" |
void applicationStart (void) |
|
{ |
void *stack; |
char *app_name; |
int rc,prio; |
|
#ifdef NETOS_GNU_TOOLS |
using namespace std; |
#endif |
|
/* Initialize the system services for the application. */ |
initAppServices(); |
|
|
/* |
* Create queues for messaging between socket threads and fpga communication thread |
*/ |
if(tx_queue_create(&inMsg, (char*)"Incoming Message Queue", TX_1_ULONG , (void*)0x300000, 4*MAX_CONNECTIONS) != SUCCESS) |
{ |
netosFatalError ((char *)"Error creating Incoming Message Queue!", 5, 5); |
} |
|
int i=0; |
currentReceiverData = new char[PACKETSIZE+2+32]; |
while(((int)(¤tReceiverData[i]))%32) i++; //Buffers used for reading from SPI need to be on a 32 byte boundary |
currentReceiverData = ¤tReceiverData[i]; |
|
/* |
* Add CLI debug stuff |
*/ |
NaCliCmd_t userTable; |
|
userTable.command_name = "rd"; |
userTable.command_func = readDebug; |
userTable.help_func = readDebugHelp; |
|
naCliAddUserTable(&userTable); |
|
/* |
* Setup SPI communication |
*/ |
NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CS, NA_GPIO_FUNC4_STATE, 0); |
NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CLK, NA_GPIO_FUNC4_STATE, 0); |
NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_RXD, NA_GPIO_FUNC4_STATE, 0); |
NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_TXD, NA_GPIO_FUNC4_STATE, 0); |
|
NASpiDeviceConfigType spiDevice0 = {0, NULL, NULL, NA_SPI_MODE2, NA_SPI_MSB, 4000000, 2000, "SPI1"}; //2, 4000000 |
|
NASpiRegisterDevice(&spiDevice0); |
|
/* |
* Start threads |
*/ |
prio = 16; |
|
|
stack = malloc (STACK_SIZE); |
if (stack == NULL) |
{ |
netosFatalError ((char *)"Unable to allocate thread stack.", 5, 5); |
} |
rc = tx_thread_create (&net_server, /* control block for thread*/ |
(char *)"Network Server thread", /* thread name*/ |
netServer, /* entry function*/ |
50000, /* parameter - port*/ |
stack, /* start of stack*/ |
STACK_SIZE, /* size of stack*/ |
prio, /* priority*/ |
prio, /* preemption threshold */ |
1, /* time slice threshold*/ |
TX_AUTO_START); /* start immediately*/ |
if (rc != TX_SUCCESS) |
{ |
netosFatalError ((char *)"Unable to create thread.", 5, 5); |
} |
|
|
|
stack = malloc (STACK_SIZE); |
if (stack == NULL) |
{ |
netosFatalError ((char *)"Unable to allocate thread stack.", 5, 5); |
} |
rc = tx_thread_create (&fpga_write, /* control block for thread*/ |
(char *)"Write to FPGA Thread", /* thread name*/ |
fpgaWrite, /* entry function*/ |
(unsigned long) 0, /* parameter*/ |
stack, /* start of stack*/ |
STACK_SIZE, /* size of stack*/ |
prio, /* priority*/ |
prio, /* preemption threshold */ |
1, /* time slice threshold*/ |
TX_AUTO_START); /* start immediately*/ |
if (rc != TX_SUCCESS) |
{ |
netosFatalError ((char *)"Unable to create thread.", 5, 5); |
} |
|
|
/* |
* Necessary threads started, suspend this thread |
*/ |
tx_thread_suspend(tx_thread_identify()); |
} |
|
|
/* |
* |
* Function: void netServer() |
* |
* Description: |
* |
* This is the netServer thread function. |
* It waits for connections, accepts these, and spawns a new socket |
* and thread to handle them. |
* Old threads are automatically cleaned up when the socket is |
* disconnected. |
* |
*/ |
void netServer(unsigned long port) |
{ |
void *stack[MAX_CONNECTIONS]; |
int rc, prio = 16, currentThreadIndex; |
int bufsize = 65536; |
|
|
for(int n=0; n<MAX_CONNECTIONS; n++) |
{ |
threadInUse[n] = FREE; |
clientSockaddrs[n] = new sockAddrIn; |
} |
|
SOCKET serverSocket; |
serverSocket = socket(AF_INET, SOCK_STREAM, 0); |
if(serverSocket == -1) |
{ |
printf("Socket Creation Error %d\n", getErrno()); |
return; |
} |
|
int error = 0; |
const int onValue = 1; |
const int offValue = 0; |
error += setsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize)); |
error += setsockopt(serverSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, sizeof(bufsize)); |
error += setsockopt(serverSocket, SOL_SOCKET, SO_BIO, (char*)&onValue, sizeof(onValue)); |
error += setsockopt(serverSocket, SOL_SOCKET, SO_NONBLOCK, (char*)&offValue, sizeof(offValue)); |
if(error != 0) |
{ |
printf("Error setting Socket options %d\n", getErrno()); |
return; |
} |
|
sockAddrIn sin(50000, INADDR_ANY); |
if(bind(serverSocket, (sockaddr *) &sin, sizeof(sin)) == -1) |
{ |
printf("Error binding Socket %d\n", getErrno()); |
return; |
} |
|
if(listen(serverSocket, MAX_CONNECTIONS) == -1) |
{ |
printf("Error listening on Socket %d\n", getErrno()); |
return; |
} |
|
int sinClientSize = sizeof(sockAddrIn); |
|
while(1) |
{ |
for(int n=0; n<MAX_CONNECTIONS; n++) |
{ |
if(threadInUse[n] == TERMINATED) |
{ |
free(stack[n]); |
tx_thread_delete(net_read[n]); |
delete net_read[n]; |
threadInUse[n] = FREE; |
} |
} |
|
currentThreadIndex = -1; |
for(int n=0; n<MAX_CONNECTIONS; n++) |
{ |
if(threadInUse[n] == FREE) |
{ |
currentThreadIndex = n; |
n = MAX_CONNECTIONS; |
} |
} |
|
if(currentThreadIndex > -1) |
{ |
if((clientSockets[currentThreadIndex] = accept(serverSocket, (sockaddr*)clientSockaddrs[currentThreadIndex], &sinClientSize)) == -1) |
{ |
printf("Error accepting client connection %d\n", getErrno()); |
return; |
} |
net_read[currentThreadIndex] = new TX_THREAD; |
|
stack[currentThreadIndex] = malloc(STACK_SIZE); |
if (stack[currentThreadIndex] == NULL) |
{ |
netosFatalError ((char *)"Unable to allocate thread stack.", 5, 5); |
} |
rc = tx_thread_create (net_read[currentThreadIndex], /* control block for thread*/ |
(char *)"Network Read thread", /* thread name*/ |
netRead, /* entry function*/ |
(unsigned long)currentThreadIndex, /* parameter - port*/ |
stack[currentThreadIndex], /* start of stack*/ |
STACK_SIZE, /* size of stack*/ |
prio, /* priority*/ |
prio, /* preemption threshold */ |
1, /* time slice threshold*/ |
TX_AUTO_START); /* start immediately*/ |
if (rc != TX_SUCCESS) |
{ |
netosFatalError ((char *)"Unable to create thread.", 5, 5); |
} |
else |
{ |
threadInUse[currentThreadIndex] = RUNNING; |
} |
} |
|
tx_thread_relinquish(); |
} |
} |
|
|
/* |
* |
* Function: void fpgaWrite() |
* |
* Description: |
* |
* This is the fpgaWrite thread function. |
* It accepts read/write requests from a message queue, and forwards these |
* to the FPGA over the SPI interface. |
* |
*/ |
void fpgaWrite(unsigned long comHandle) |
{ |
char* writeBuffer; |
char* readBuffer; |
char* temp; |
unsigned long currentIndex; |
int i=0; |
|
readBuffer = new char[PACKETSIZE+2+32]; |
|
while(((int)(&readBuffer[i]))%32) i++; |
|
readBuffer = &readBuffer[i]; |
|
while(1) |
{ |
if(tx_queue_receive(&inMsg, &writeBuffer, TX_NO_WAIT) == TX_SUCCESS) |
{ |
currentIndex = writeBuffer[PACKETSIZE]; |
for(int n=0; n<PACKETSIZE; n++) |
{ |
readBuffer[n] = 0; |
} |
|
NASpiReadWrite("SPI1", (char*)writeBuffer, (char*)readBuffer, PACKETSIZE); |
|
if(((int*)writeBuffer)[0] & DO_COMMIT_READ_PRE) |
{ |
((int*)writeBuffer)[0] &= ~(DO_COMMIT_READ_PRE + DO_COMMIT_WRITE_PRE + DO_WRITE + DO_COMMIT_WRITE_POST); |
|
do |
{ |
tx_thread_relinquish(); |
NASpiReadWrite("SPI1", (char*)writeBuffer, (char*)readBuffer, PACKETSIZE); |
debug[0] = ((int*)readBuffer)[0]; |
debug[1] = ((int*)readBuffer)[1]; |
} |
while(((unsigned int*)readBuffer)[0] > 1); |
} |
|
if(((int*)writeBuffer)[0] & DO_READ) |
{ |
while(currentReceiverIndex != MAX_CONNECTIONS) |
{ |
tx_thread_relinquish(); |
} |
|
temp = readBuffer; |
readBuffer = currentReceiverData; |
currentReceiverData = temp; |
currentReceiverIndex = currentIndex; |
} |
} |
tx_thread_relinquish(); |
} |
} |
|
/* |
* |
* Function: void netRead(unsigned long threadIndex) |
* |
* Description: |
* |
* This is the netRead thread function. |
* It is spawned for every new connection made to the netServer, and |
* handles the necessary communication. |
* |
* Parameters: |
* |
* threadIndex - The global index of the thread. Used for indexing into |
* the global thread status variables. |
* |
*/ |
void netRead(unsigned long threadIndex) |
{ |
char* buffer; |
int temp; |
char backupTemp; |
|
buffer = new char[PACKETSIZE + 2]; |
buffer[PACKETSIZE] = '\0'; |
bool doRead, doWrite; |
|
while(1) |
{ |
if((temp = recv(clientSockets[threadIndex], buffer, PACKETSIZE, 0)) < 1) |
{ |
threadInUse[threadIndex] = TERMINATED; |
delete [] buffer; |
closesocket(clientSockets[threadIndex]); |
tx_thread_terminate(tx_thread_identify()); |
} |
else |
{ |
for(int n=0; n<(PACKETSIZE/4); n++) |
{ |
backupTemp = buffer[n*4]; |
buffer[n*4] = buffer[n*4+3]; |
buffer[n*4+3] = backupTemp; |
backupTemp = buffer[n*4+2]; |
buffer[n*4+2] = buffer[n*4+1]; |
buffer[n*4+1] = backupTemp; |
} |
|
buffer[PACKETSIZE+1] = '\0'; |
buffer[PACKETSIZE] = threadIndex; |
|
doRead = ((int*)buffer)[0] & DO_READ; |
doWrite = ((int*)buffer)[0] & DO_WRITE; |
|
if(doWrite && (temp < 8)) |
{ |
((int*)buffer)[0] &= ~(DO_COMMIT_WRITE_PRE + DO_WRITE + DO_COMMIT_WRITE_POST); |
} |
|
if(!doRead) |
{ |
((int*)buffer)[0] &= ~(DO_COMMIT_READ_PRE); |
} |
|
tx_queue_send(&inMsg, &buffer, TX_NO_WAIT); |
|
if(doRead) |
{ |
while(currentReceiverIndex != threadIndex) |
{ |
tx_thread_relinquish(); |
} |
|
backupTemp = (&(currentReceiverData[4]))[0]; |
(&(currentReceiverData[4]))[0] = (&(currentReceiverData[4]))[3]; |
(&(currentReceiverData[4]))[3] = backupTemp; |
backupTemp = (&(currentReceiverData[4]))[2]; |
(&(currentReceiverData[4]))[2] = (&(currentReceiverData[4]))[1]; |
(&(currentReceiverData[4]))[1] = backupTemp; |
|
send(clientSockets[threadIndex], (&(currentReceiverData[4])), 4, 0); |
|
currentReceiverIndex = MAX_CONNECTIONS; |
} |
} |
|
tx_thread_relinquish(); |
} |
} |
|
|
int readDebug(int fd, int n, char * args[]) |
{ |
naCliPrintf(fd, "Read values: %.8x | %.8x\n\r", debug[0], debug[1]); |
|
return 0; |
} |
|
int readDebugHelp(int fd, int n, char * args[]) |
{ |
naCliPrintf(fd, "Prints the six first integers in the read-array from the SPI transfer"); |
|
return 0; |
} |
|
/trunk/software/Digi_app/readme.txt
0,0 → 1,81
|
uTosNet_spi Digi application, readme.txt |
|
Simon Falsig |
University of Southern Denmark |
Copyright 2010 |
|
This file is part of the uTosNet_spi Digi application |
|
The uTosNet_spi Digi application is free software: you can redistribute it |
and/or modify it under the terms of the GNU Lesser General Public License as |
published by the Free Software Foundation, either version 3 of the License, |
or (at your option) any later version. |
|
The uTosNet_spi Digi application is distributed in the hope that it will be |
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
General Public License for more details. |
|
You should have received a copy of the GNU Lesser General Public License |
along with the uTosNet_spi Digi application. If not, see |
<http://www.gnu.org/licenses/>. |
|
|
****************************************** |
* Description |
****************************************** |
The uTosNet_spi Digi application is meant for use with the Ethernet/SPI |
version of uTosNet. It provides the server application that should run |
on the Digi Connect ME 9210 microcontroller module, in order for it to |
work with the uTosNet_spi FPGA module and PC application. |
|
****************************************** |
* Building |
****************************************** |
Use the Digi IDE to create a new project, and use the accompanying |
root.cxx file as the main file. Then build and download it according |
to standard Digi procedures. |
|
****************************************** |
* Usage |
****************************************** |
The server application listens on port 50000, and uses a binary protocol. |
It accepts the following kinds of packets: |
(for all packets bit 31 is MSB, all unspecified bits should be '0') |
|
|
- Read request (32 bits): |
- Bit 29: Set to '1' |
- Bit 25-16: Set to read address |
- Set all others to '0' |
|
Response (32 bits): |
- Bit 31-0: Contains read data |
|
|
- Write request (2x32 bits): |
First 32 bits: |
- Bit 11: Set to '1' |
- Bit 9-0: Set to write address |
Second 32 bits: |
- Bit 31-0: Set to write data |
|
Response: None |
|
|
- Combined read/write (2x32 bits) |
First 32 bits: |
- Bit 29: Set to '1' |
- Bit 25-16: Set to read address |
- Bit 11: Set to '1' |
- Bit 9-0: Set to write address |
Second 32 bits: |
- Bit 31-0: Set to write data |
|
Response (32 bits): |
- Bit 31-0: Contains read data |
|
****************************************** |
* End of file |
****************************************** |