= Network = == Network File System (NFS) == It is helpful to setup an NFS share on your host computer for application testing. You may place your executables to be tested in the directory and access them from the target hardware. Using PuTTY, MiniCom, HyperTerminal or another communications program to communicate with the debug serial port 115000 8N1 the prompt should appear as: {{{ # }}} Type: {{{ # mount –t nfs 192.168.1.100:/srv/nfs /mnt/nfs –o nolock }}} Replace "192.168.1.100:/srv/nfs" with the appropriate IP address and share name of your NFS share. "/srv/nfs" is NFS share name already configured when using the VMware development image. Type: {{{ # cd /mnt/nfs }}} to change to the NFS directory. You can then run an application directly from the NFS folder without having to copy it to the 825 NAND. Make sure the application is flagged as executable from the host. To set a file as executable: {{{ # chmod +x indicator }}} To run the application type: {{{ # ./indicator & }}} To run an application named indicator. Note the "./" at the beggining is needed to tell the OS to run the executable in the current directory. Alternatively, you may run the executable file by specifying the full path: {{{ # /mnt/nfs/indicator & }}} The "&" symbol specifies that the application will run in a new thread so you may continue to type commands, for example to check memory or copy files while the program is running. If the "&" symbol is not specified the terminal will be locked until the program exits or "CTRL-C" from the terminal will usually be able to stop the execution. To stop a running application type: {{{ # ps }}} This will list the running processes: {{{ PID TTY TIME CMD 1 ? 00:00:02 init 2 ? 00:00:00 kthreadd 3 ? 00:00:00 migration/0 4 ? 00:00:00 ksoftirqd/0 5 ? 00:00:00 watchdog/0 6 ? 00:00:00 migration/1 7 ? 00:00:00 ksoftirqd/1 8 ? 00:00:00 watchdog/1 9 ? 00:00:00 events/0 10 ? 00:00:00 events/1 11 ? 00:00:00 khelper 85 ? 00:00:00 kintegrityd/0 86 ? 00:00:00 kintegrityd/1 88 ? 00:00:00 kblockd/0 89 ? 00:00:00 kblockd/1 91 ? 00:00:00 kacpid 92 ? 00:00:00 kacpi_notify }}} Identify the PID number of the process to stop and type: {{{ # kill (where is the appropriate process ID) }}} The "pidof" statement allows for another method of stopping a process: {{{ # kill 'pidof indicator' }}} Note if you accidentally press ENTER before closing the apostrophe you may get a prompt: {{{ > }}} It is not possible to get out of this prompt until a closing apostrophe "'" is typed and ENTER is pressed: {{{ >' Unknown command # }}} At times you may lose track of your current path. To check the current path type: {{{ # pwd }}} This will respond with the current path such as “/mnt/nfs”. == Weight Server -- Network Access == The 825 weight server feature allows remote control operations to be performed via a network connection. The weight server also allows weight data to be accessed via a network connection. The weight data may be accessed using SMA commands such as "W" from a client to request the weight or the legacy CTRL-E request for 738 computer format data. This also network access to the 825 from various software such as Cardinal WinVRS or Cardinal WinDDE. == Network Programming == Programs may be written utilizing many of the common Linux network libraries. Programs may be written to act as a TCP/IP server waiting for connections from clients. This is similar to the 825 weight server. The below example is helpful for learning TCP/IP client/server programming. For most 825 apps it is recommended to use the [wiki:Docs/Prog/Manual/ApplicationLibraries/lib825ev/Comm/CComm CComm] class provided in lib825ev instead. === 825 TCP/IP Server Example === {{{ // TCP/IP Server Demo #include #include #include #include #include #include #include #include #include #include #include #include #include /* socket, bind, accept */ #include /* socket, bind, accept, setsockopt, */ #include /* open */ #include using namespace std; const int BUFSIZE = 30; // To allow for multiple-byte requests from clients we have to keep a separate receive buffer for each client struct client_info { int socket; char buf[BUFSIZE]; int pos; }; // Dynamic list to keep track of connected clients vector client_list; int server_s; const int sock_opt = 1; const int nPort = 10010; // Change to use a different TCP/IP port int ServerProcess(void) { int i; int client_s; struct sockaddr_in addr; socklen_t socklen = sizeof(addr); // Check for new client connections client_s = accept(server_s, (sockaddr*)&addr, &socklen); if(client_s >= 0) { char szIP[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &addr.sin_addr, szIP, INET_ADDRSTRLEN); printf("TCP/IP server connection from IP %s socket %d\r\n", szIP, client_s); /* nonblocking socket */ if(fcntl(client_s, F_SETFL, O_NONBLOCK) == -1) { printf("fcntl: unable to set new socket to non-block\r\n"); close(client_s); } else { // Add client information to list of connected clients client_info info; info.socket = client_s; info.pos = 0; client_list.push_back(info); } } // Service any connected clients if(client_list.size() > 0) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; // Load up structure for "select" statement to check for receive data from all connected clients fd_set rfds; FD_ZERO(&rfds); int nMaxfd = 0; for(i = 0; i < (int)client_list.size(); i++) { FD_SET(client_list[i].socket, &rfds); if(client_list[i].socket > nMaxfd) nMaxfd = client_list[i].socket; } int retval = select(nMaxfd + 1, &rfds, NULL, NULL, &tv); if(retval == -1) { printf("select return -1\r\n"); } else if(retval > 0) { int rcvlen; char data[20], sendbuf[50]; int z; int remove = -1; // Loop through array of all connected clients for(i = 0; i < (int)client_list.size(); i++) { // Select statement will have loaded rfds to identify which clients have data available to read from if(FD_ISSET(client_list[i].socket, &rfds)) { rcvlen = recv(client_list[i].socket, data, sizeof(data), 0); // Loop through bytes received from this client for(z = 0; z < rcvlen; z++) { // If ENTER we have completed message - otherwise add character to the client read buffer if(data[z] == '\r') { // Must terminate the string client_list[i].buf[client_list[i].pos] = '\0'; printf("Socket %d message [%s]\r\n", client_list[i].socket, client_list[i].buf); // In this sample we check for "TIME" received and respond with the server time if(!strcmp(client_list[i].buf, "TIME")) { // Get current time time_t rawtime; struct tm *timeinfo; time(&rawtime); timeinfo = localtime(&rawtime); // Format time into string sprintf(sendbuf, "Server time is: %02d:%02d:%02d ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); // Send to client send(client_list[i].socket, sendbuf, strlen(sendbuf), 0); } // Reset the buffer position for the next request client_list[i].pos = 0; } else { // Add character to buffer client_list[i].buf[client_list[i].pos++] = data[z]; // In case of overflow reset position to prevent overwriting memory and crashing if(client_list[i].pos >= BUFSIZE) client_list[i].pos = 0; } } if(rcvlen <= 0) { // If the receive length is zero or negative indicates an error - we lost the connection // Set variable remove to indicate this client should be removed printf("recv Error %d\r\n", rcvlen); remove = i; } } } if(remove >= 0) { // If a client disconnected remove it from the list printf("Removing %d client socket %d\r\n", remove, client_list[remove].socket); client_list.erase(client_list.begin() + remove); } } } return 0; } int main() { // Create the server socket server_s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if(server_s == -1) { printf("unable to create socket\r\n"); return -1; } // Set server socket to be nonblocking if(fcntl(server_s, F_SETFL, O_NONBLOCK) == -1) { printf("fcntl: unable to set server socket to nonblocking"); return -1; } // Set server to reuse socket addresses if((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt, sizeof (sock_opt))) == -1) { printf("setsockopt"); } // Prepare sockaddr structure before binding struct sockaddr_in server_sockaddr; memset(&server_sockaddr, 0, sizeof server_sockaddr); server_sockaddr.sin_family = PF_INET; server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); server_sockaddr.sin_port = htons(nPort); // Bind the socket address if(bind(server_s, (struct sockaddr *) &server_sockaddr, sizeof (server_sockaddr)) == -1) { printf("Unable to bind\r\n"); return -1; } // Begin listening for clients to connect if(listen(server_s, 10) == -1) { printf("unable to listen"); } struct timespec delaytm; delaytm.tv_sec = 0; delaytm.tv_nsec = 8000000; // Processing loop while(1) { ServerProcess(); // Small time delay to help OS perform its processing at a smooth rate nanosleep(&delaytm, NULL); } return 0; } }}} The server may be tested by running it on a networked 825. Use a PC connected to the network running a terminal program such as Hyperterm or CommView. Select the appropriate IP address of the indicator, and port 10010. In the terminal type TIME and the 825 server should respond with the time of the 825 indicator. === 825 TCP/IP Client Example === {{{ // TCP/IP Client Example #include #include #include #include #include #include #include #include #include #define CHR_STX 0x02 #define CHR_ETX 0x03 #define IP_ADDR "90.1.2.202" #define IP_PORT 3000 #define START_CHR CHR_STX #define STOP_CHR CHR_ETX enum RcvMode { rcvIdle, rcvData }; #define RCVMODE_IDLE 0 #define RCVMODE_DATA 1 /* * This example connects to the server * When a properly formatted message message is received from the server * it is sent back to the server * */ int main() { struct sockaddr_in serv_addr; struct hostent *svr; char buffer[50], rcv_buf[50]; int sockfd, n, i, rcv_pos = 0; RcvMode rcvMode = rcvIdle; sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd < 0) { printf("error\r\n"); return -1; } svr = gethostbyname(IP_ADDR); if(svr == NULL) { printf("error getHostbyname\r\n"); return -1; } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; memcpy(&serv_addr.sin_addr.s_addr, svr->h_addr_list[0], sizeof(serv_addr.sin_addr.s_addr)); serv_addr.sin_port = htons(IP_PORT); if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { printf("error connecting\r\n"); return -1; } // Set the socket to be non-blocking if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) { printf("fcntl: unable to set non-blocking\r\n"); } printf("Connected to server %s port %d waiting for message from server\r\n", IP_ADDR, IP_PORT); while(1) { n = read(sockfd, buffer, sizeof(buffer)); // We are not blocking. You must copy to another buffer to be sure to get a complete message // For example in one iteration of the loop you might receive: // This is a // and the nest iteration of the loop may give you: // test message if(n > 0) { for(i = 0; i < n; i++) { if(rcvMode == rcvIdle) { if(buffer[i] == START_CHR) { rcvMode = rcvData; } } else { if(buffer[i] == STOP_CHR) { rcv_buf[rcv_pos] = '\0'; printf("Message received [%s]\r\n", rcv_buf); // Send back the message without the and send(sockfd, rcv_buf, strlen(rcv_buf), 0); rcv_pos = 0; rcvMode = rcvIdle; } else if(rcv_pos < (int)(sizeof(rcv_buf) - 1)) { rcv_buf[rcv_pos++] = buffer[i]; } } } } } return 0; } }}} This client program may be tested by running it on a networked 825. A PC may be connected on the network running CommView in server mode. Set the port to 3000. In the CommView make a function key to output: %02This is test%03 When this function key is pressed the 825 will display "This is a test" and the message will also be sent back to the CommView server. == Send E-mail from 825 == Sending an e-mails can be performed from the command line or using a system call from an application. {{{ $ echo "Test email" > /tmp/email.txt $ sendmail -U user@provider.com -P password -t joe@somewhere.com -s "S ubject line" smtp.mailserver.com:25 user@provider.com /tmp/email.txt }}} This requires access to an e-mail server that does not require an encrypted connection. == FTP == The 825 has limited ftp command line ability to send files. This only supports very basic unsecured ftp file servers. ftpput [OPTIONS] HOST REMOTE_FILE LOCAL_FILE Store a local file on a remote machine via FTP Options: -v,--verbose Verbose -u,--username Username -p,--password Password -P,--port Port number == Batch file to upload a file from a PC to an 825 using the 825 web server and cURL (tested with Windows 10) == For Windows 10 version 1803 and above, cURL now ships by default in the Command Prompt. {{{ rem - send825file.bat Batch file to upload a file from a PC to an 825 using the 825 web server and Windows 10 cURL rem - usage: send825file.bat ipaddr filepath dir825 user password rem - example: send825file.bat 10.1.0.179 c:\testfile6.txt /mnt/nand/apps/ ADMIN ***** rem - CAUTION: make sure 825 path has trailing slash otherwise file will be written such as /mnt/nand/appstestfile6.txt set ip=%1 set filename=%2 set dir825=%3 set user=%4 set password=%5 set cookiesfile=%userprofile%\Downloads\cookies825.txt rem - Login to the 825 web server curl -v -b %cookiesfile% -c %cookiesfile% "http://%ip%/cgi-bin/index?p=login&a=login" --data "user=%user%&password=%password%" timeout 5 rem - Set the directory the file will be uploaded to curl -v -b %cookiesfile% -c %cookiesfile% "http://%ip%/cgi-bin/index?p=filemgr&a=cd&d=%dir825%" timeout 5 rem - Upload the file curl -v -b %cookiesfile% -c %cookiesfile% -F file=@%filename% "http://%ip%/cgi-bin/index?p=filemgr&a=new" }}} == Batch file to download a file from an 825 to a PC using the 825 web server and cURL (tested with Windows 10) == {{{ rem - rcv825file.bat Batch file to download a file from an 825 to a PC using the 825 web server and Windows 10 cURL rem - usage: rcv825file.bat ipaddr dir825 filename tofile user password rem - example: rcv825file.bat 10.1.0.179 /mnt/nand/apps/ testfile6.txt C:\tstfile.txt ADMIN ***** rem - CAUTION: make sure 825 path has trailing slash set ip=%1 set dir825=%2 set filename=%3 set topath=%4 set user=%5 set password=%6 set cookiesfile=%userprofile%\Downloads\cookies825.txt rem - Login to the 825 web server curl -v -b %cookiesfile% -c %cookiesfile% "http://%ip%/cgi-bin/index?p=login&a=login" --data "user=%user%&password=%password%" timeout 5 rem - Set the directory the file will be downloaded from curl -v -b %cookiesfile% -c %cookiesfile% "http://%ip%/cgi-bin/index?p=filemgr&a=cd&d=%dir825%" timeout 5 rem - Download the file curl -v -b %cookiesfile% -c %cookiesfile% -o %topath% "http://%ip%/cgi-bin/index?p=filemgr&a=dl&n=%filename%" }}}