Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
mbtcp.cpp
- Committer:
- paleskyjp
- Date:
- 2012-03-16
- Revision:
- 0:8ee5ec4bcec2
File content as of revision 0:8ee5ec4bcec2:
/*
* FreeModbus Libary: mbed Port
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: porttcp.c,v 1.1 2006/08/30 23:18:07 wolti Exp $
*
* modified by Yuji Hosogaya 3-16-2012
*
* Originally this file was porttcp.c, then combined with other files
* in order to make a light version of Modbus TCP.
*/
#include "mbtcp.h"
Ethernet ethernet;
struct netif netif_data;
/* ----------------------- MBAP Header --------------------------------------*/
#define MB_TCP_UID 6
#define MB_TCP_LEN 4
#define MB_TCP_FUNC 7
/* ----------------------- Defines -----------------------------------------*/
#define MB_TCP_DEFAULT_PORT 502 /* TCP listening port. */
#define MB_TCP_BUF_SIZE ( 256 + 7 ) /* Must hold a complete Modbus TCP frame. */
/* ----------------------- Static variables ---------------------------------*/
static UCHAR aucTCPBuf[MB_TCP_BUF_SIZE];
static USHORT usTCPBufPos;
/* ----------------------- Begin implementation -----------------------------*/
void EventPost(struct tcp_pcb *pcb)
{
USHORT usAddress,usNRegs;
UCHAR txbuf[MB_TCP_BUF_SIZE];
int len=0;
UCHAR ucTemp;
MB_STRUCT *rxmbs=(MB_STRUCT *)aucTCPBuf;
MB_STRUCT *txmbs=(MB_STRUCT *)txbuf;
MB_WORD_REQ *wd_req=(MB_WORD_REQ *)GET_DATA_PTR(rxmbs);
MB_WORD_RES *wd_res=(MB_WORD_RES *)GET_DATA_PTR(txmbs);
usAddress=TO_USHORT(wd_req->ADDR_H,wd_req->ADDR_L)+1;
usNRegs=TO_USHORT(wd_req->LEN_H,wd_req->LEN_L);
printf("TID=%04X | PID=%04X | LEN=%04X | UID=%02X | FUNC=%02X\nDATA=",
GET_TID(rxmbs), GET_PID(rxmbs), GET_LEN(rxmbs), GET_UID(rxmbs), GET_FUNC(rxmbs) );
for(int i=0;i<usTCPBufPos-8;i++){
printf("%02X",aucTCPBuf[i+8]);
}
printf("\n");
switch(GET_FUNC(rxmbs))
{
case FC_RD_COILS:
memcpy((char*)txmbs,(char*)rxmbs,8);
wd_res->BYTES=usNRegs*2;
len=usNRegs/8;
if(usNRegs%8!=0)len++;
SET_LEN(txmbs,len+3);
wd_res->BYTES=(UCHAR)len;
eMBRegCoilsCB( (UCHAR *) &wd_res->DATA, usAddress, usNRegs, MB_REG_READ);
len+=9;
break;
case FC_RD_DISC_INPUTS:
memcpy((char*)txmbs,(char*)rxmbs,8);
wd_res->BYTES=usNRegs*2;
len=usNRegs/8;
if(usNRegs%8!=0)len++;
SET_LEN(txmbs,len+3);
wd_res->BYTES=(UCHAR)len;
eMBRegDiscreteCB( (UCHAR *) &wd_res->DATA, usAddress, usNRegs );
len+=9;
break;
case FC_RD_HOLDING_REGS:
memcpy((char*)txmbs,(char*)rxmbs,8);
wd_res->BYTES=usNRegs*2;
len=usNRegs*2;
SET_LEN(txmbs,len+3);
eMBRegHoldingCB( (UCHAR *)&wd_res->DATA, usAddress, usNRegs, MB_REG_READ);
len+=9;
break;
case FC_RD_INPUT_REGS:
memcpy((char*)txmbs,(char*)rxmbs,8);
wd_res->BYTES=usNRegs*2;
len=usNRegs*2;
SET_LEN(txmbs,len+3);
eMBRegInputCB( (UCHAR *)&wd_res->DATA, usAddress, usNRegs );
len+=9;
break;
case FC_WR_SINGLE_COIL:
ucTemp=(wd_req->LEN_H==0x00)?0:1;
len=12;
memcpy((char*)txmbs,(char*)rxmbs,len);
eMBRegCoilsCB( &ucTemp, usAddress, 1, MB_REG_WRITE);
break;
case FC_WR_SINGLE_REG:
len=12;
memcpy((char*)txmbs,(char*)rxmbs,12);
eMBRegHoldingCB( &wd_req->LEN_H, usAddress, 1, MB_REG_WRITE );
break;
case FC_WR_MULTI_COILS:
len=12;
memcpy((char*)txmbs,(char*)rxmbs,len);
SET_LEN(txmbs,6);
eMBRegCoilsCB( &wd_req->DATA[1], usAddress, usNRegs, MB_REG_WRITE);
break;
case FC_WR_MULTI_REGS:
len=12;
memcpy((char*)txmbs,(char*)rxmbs,len);
SET_LEN(txmbs,6);
eMBRegHoldingCB( &wd_req->DATA[1], usAddress, usNRegs, MB_REG_WRITE);
break;
case FC_RD_WR_MULTI_REGS:
memcpy((char*)txmbs,(char*)rxmbs,8);
// Write operation
eMBRegHoldingCB( &wd_req->DATA[5], usAddress, usNRegs, MB_REG_WRITE);
// Read operation
usAddress=TO_USHORT(wd_req->DATA[0],wd_req->DATA[1])+1;
usNRegs=TO_USHORT(wd_req->DATA[2],wd_req->DATA[3]);
eMBRegHoldingCB( &wd_res->DATA, usAddress, usNRegs, MB_REG_READ);
len=usNRegs*2;
wd_res->BYTES=len;
SET_LEN(txmbs,len+3);
len+=9;
break;
default:
printf("UNSUPPORTED FUNCTION CODE\n");
break;
}
if(len>0){
for(int i=0;i<len;i++){
printf("%02X ",txbuf[i]);
}
printf("\n\n");
if (tcp_write(pcb, (void *)txbuf, len, 1) == ERR_OK) {
tcp_output(pcb);
}else{
printf("Failed to send a response!!\n");
}
}
}
err_t recv_callback(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
struct netif *netif = &netif_data;
unsigned short usLength;
int i;
/* Check if status is ok and data is arrived. */
if (err == ERR_OK && p != NULL) {
/* Inform TCP that we have taken the data. */
tcp_recved(pcb, p->tot_len);
memcpy( &aucTCPBuf[usTCPBufPos], p->payload, p->tot_len );
usTCPBufPos += p->tot_len;
if( usTCPBufPos >= MB_TCP_FUNC )
{
/* Length is a byte count of Modbus PDU (function code + data) and the
* unit identifier. */
usLength = aucTCPBuf[MB_TCP_LEN] << 8U;
usLength |= aucTCPBuf[MB_TCP_LEN + 1];
/* Is the frame already complete. */
if( usTCPBufPos < ( MB_TCP_UID + usLength ) )
{
}
else if( usTCPBufPos == ( MB_TCP_UID + usLength ) )
{
for(i=0;i<usTCPBufPos;i++){
printf("%02X ",aucTCPBuf[i]);
}
printf("\n");
EventPost(pcb);
usTCPBufPos=0;
}
else
{
printf("Received to many bytes! Droping client.\n" );
/* This should not happen. We can't deal with such a client and
* drop the connection for security reasons.
*/
//vvMBPortReleaseClient( pxPCB );
}
}
pbuf_free(p);
}else{
/* No data arrived */
/* That means the client closes the connection and sent us a packet with FIN flag set to 1. */
/* We have to cleanup and destroy out TCPConnection. */
printf("Connection closed by client.\r\n");
pbuf_free(p);
}
return ERR_OK;
}
/* Accept an incomming call on the registered port */
err_t accept_callback(void *arg, struct tcp_pcb *npcb, err_t err) {
LWIP_UNUSED_ARG(arg);
/* Subscribe a receive callback function */
tcp_recv(npcb, &recv_callback);
/* Don't panic! Everything is fine. */
printf("accepted connection\n");
usTCPBufPos=0;
return ERR_OK;
}
void mb_init()
{
struct netif *netif = &netif_data;
struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gateway;
Ticker tickFast, tickSlow, tickARP, eth_tick, dns_tick, dhcp_coarse, dhcp_fine;
char *hostname = "my-mbed";
printf("Setting up...\n");
/* Start Network with DHCP */
IP4_ADDR(&netmask, 255,255,255,255);
IP4_ADDR(&gateway, 0,0,0,0);
IP4_ADDR(&ipaddr, 0,0,0,0);
/* Initialise after configuration */
lwip_init();
netif->hwaddr_len = ETHARP_HWADDR_LEN;
device_address((char *)netif->hwaddr);
netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, device_init, ip_input);
netif->hostname = hostname;
netif_set_default(netif);
dhcp_start(netif); // <-- Use DHCP
/* Initialise all needed timers */
tickARP.attach_us( ðarp_tmr, ARP_TMR_INTERVAL * 1000);
tickFast.attach_us(&tcp_fasttmr, TCP_FAST_INTERVAL * 1000);
tickSlow.attach_us(&tcp_slowtmr, TCP_SLOW_INTERVAL * 1000);
dns_tick.attach_us(&dns_tmr, DNS_TMR_INTERVAL * 1000);
dhcp_coarse.attach_us(&dhcp_coarse_tmr, DHCP_COARSE_TIMER_MSECS * 1000);
dhcp_fine.attach_us(&dhcp_fine_tmr, DHCP_FINE_TIMER_MSECS * 1000);
while (!netif_is_up(netif)) {
device_poll();
}
printf("Setup OK\n");
printf("mbed IP Address is: %d.%d.%d.%d\n", (netif->ip_addr.addr)&0xFF, (netif->ip_addr.addr>>8)&0xFF, (netif->ip_addr.addr>>16)&0xFF, (netif->ip_addr.addr>>24)&0xFF);
/* Bind a function to a tcp port */
struct tcp_pcb *pcb = tcp_new();
if (tcp_bind(pcb, IP_ADDR_ANY, 502) == ERR_OK) {
pcb = tcp_listen(pcb);
tcp_accept(pcb, &accept_callback);
}
}