Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/powerpmac_simulator_setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

# Running an EPICS IOC Against the Power PMAC Simulator

This guide explains how to run an EPICS IOC (Input/Output Controller) against the Power PMAC simulator. This is useful for development and testing of EPICS support without requiring physical hardware.

## Step 1: Launch the Power PMAC Simulator

1. Run the Power PMAC Simulator.
2. Choose the desired CPU.
3. Start the simulator and confirm it is running with the default IP address `172.20.0.200`.
4. Ensure SSH access is enabled on the Windows workstation.

## Step 2: Forward the SSH Port

From your Linux development host, forward the simulator's SSH port using:

```bash
ssh -L 2222:172.20.0.200:22 $USER@<windows-workstation-hostname-or-ip>
```

Enter your password if requested.

## Step 3: Run the IOC

Configure the IOC to use the forwarded SSH port with the `pmacAsynSSHPort` class:

```tcl
# st.cmd
< envPaths
cd ${TOP}

# Use SSH port forwarding to connect to simulator
pmacAsynSSHPortConfigure("SIM_PMAC_PORT", "localhost", 2222, "root", "deltatau")

# Create the PMAC controller
pmacCreateController("SIM_PMAC", "SIM_PMAC_PORT", 0, 0)
```

Start the IOC:

```bash
./bin/linux-x86_64/pmacSim st.cmd
```

You should see output indicating a successful SSH connection to the simulator.

## Notes

- The simulator does not emulate all hardware features. Some commands may not behave identically to a real PMAC.
- SSH port forwarding allows secure and flexible access to the simulator from remote development environments.
8 changes: 5 additions & 3 deletions etc/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ class pmacAsynSSHPort(DeltaTauSSHCommsPort):
DbdFileList = ['drvAsynPowerPMACPort']
_Cards = []

def __init__(self, name, IP, USERNAME='root', PASSWORD='deltatau', PRIORITY=0, NOAUTOCONNECT=0, NOEOS=0, simulation=None):
def __init__(self, name, IP, SSHPORT=22, USERNAME='root', PASSWORD='deltatau', PRIORITY=0, NOAUTOCONNECT=0, NOEOS=0, simulation=None):
self.IP = IP
self.SSHPORT = SSHPORT
self.USERNAME = USERNAME
self.PASSWORD = PASSWORD
self.PRIORITY = PRIORITY
Expand All @@ -78,13 +79,14 @@ def __init__(self, name, IP, USERNAME='root', PASSWORD='deltatau', PRIORITY=0, N
self.__super.__init__(name)

def Initialise(self):
print '# Create SSH Port (PortName, IPAddress, Username, Password, Priority, DisableAutoConnect, noProcessEos)'
print 'drvAsynPowerPMACPortConfigure("%(name)s", "%(IP)s", "%(USERNAME)s", "%(PASSWORD)s", "%(PRIORITY)d", "%(NOAUTOCONNECT)d", "%(NOEOS)d")' % \
print '# Create SSH Port (PortName, IPAddress, SSHPort, Username, Password, Priority, DisableAutoConnect, noProcessEos)'
print 'drvAsynPowerPMACPortConfigure("%(name)s", "%(IP)s", "%(SSHPORT)d","%(USERNAME)s", "%(PASSWORD)s", "%(PRIORITY)d", "%(NOAUTOCONNECT)d", "%(NOEOS)d")' % \
self.__dict__

ArgInfo = makeArgInfo(__init__,
name = Simple('Port Name, normally something like SSH_PORT', str),
IP = Simple('IP address of the powerPMAC', str),
SSHPORT = Simple('SSH Port of the powerPMAC', int),
USERNAME = Simple('Username for the SSH connection', str),
PASSWORD = Simple('Password for the SSH connection', str),
PRIORITY = Simple('Priority of the port', int),
Expand Down
2 changes: 1 addition & 1 deletion etc/makeIocs/lab-ppmac.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" ?>
<components arch="linux-x86_64">
<!--Giles Test Power Clipper-->
<pmac.pmacAsynSSHPort IP="172.23.240.160" name="BRICK1port"/>
<pmac.pmacAsynSSHPort IP="172.23.240.160" SSHPORT="22" name="BRICK1port"/>
<!--Lab Power Brick-->
<!--<pmac.pmacAsynSSHPort IP="172.23.247.1" name="BRICK1port"/>-->
<!--<EPICS_BASE.dbpf pv="BRICK1:FEEDRATE" value="100"/>-->
Expand Down
2 changes: 1 addition & 1 deletion etc/makeIocs/powerPMAC.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" ?>
<components arch="linux-x86_64">
<pmac.pmacAsynSSHPort IP="172.23.247.1" name="SSH1"/>
<pmac.pmacAsynSSHPort IP="172.23.247.1" SSHPORT="22" name="SSH1"/>
<pmac.PowerPMAC P="POWER" Port="SSH1" name="PowerPMAC.pmac"/>
<pmac.PowerPmacStatus DEVICE="POWER" NAXES="8" PLC="5" PORT="PowerPMAC.pmac" name="PowerPMAC.STAT"/>
<pmac.CS CS="2" Controller="PowerPMAC.pmac" name="PowerPMAC.CS2"/>
Expand Down
28 changes: 18 additions & 10 deletions pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ typedef struct {
asynUser *pasynUser; /* Not currently used */
char *SSHDeviceName;
char *SSHHostName;
unsigned int SSHPortNumber;
char *SSHUserName;
char *SSHPassword;
char *portName;
Expand Down Expand Up @@ -138,7 +139,7 @@ connectIt(void *drvPvt, asynUser *pasynUser)


// Create the driver
ssh->fd = new SSHDriver(ssh->SSHHostName);
ssh->fd = new SSHDriver(ssh->SSHHostName, ssh->SSHPortNumber);

// Set the username
ssh->fd->setUsername(ssh->SSHUserName);
Expand Down Expand Up @@ -285,7 +286,7 @@ static asynStatus readIt(void *drvPvt, asynUser *pasynUser,
/* If there is room add a null byte */
if (thisRead < maxchars)
data[thisRead] = 0;
else
else
reason |= ASYN_EOM_CNT;
//printf("*** Reason: %d\n", reason);
if (gotEom) *gotEom = reason;
Expand Down Expand Up @@ -342,6 +343,7 @@ static const struct asynCommon drvAsynPowerPMACPortAsynCommon = {
epicsShareFunc int
drvAsynPowerPMACPortConfigure(const char *portName,
const char *hostName,
unsigned int sshPortNumber,
const char *userName,
const char *password,
unsigned int priority,
Expand All @@ -366,6 +368,10 @@ drvAsynPowerPMACPortConfigure(const char *portName,
printf("PowerPMAC host name missing.\n");
return -1;
}
if (sshPortNumber < 1 || sshPortNumber > 65535) {
printf("PowerPMAC SSH port number %d is out of valid range (0-65535).\n", sshPortNumber);
return -1;
}
if (userName == NULL) {
printf("PowerPMAC user name missing.\n");
return -1;
Expand All @@ -382,6 +388,7 @@ drvAsynPowerPMACPortConfigure(const char *portName,
ssh->fd = NULL;
ssh->SSHDeviceName = epicsStrDup(hostName);
ssh->SSHHostName = epicsStrDup(hostName);
ssh->SSHPortNumber = sshPortNumber;
ssh->SSHUserName = epicsStrDup(userName);
ssh->SSHPassword = epicsStrDup(password);
ssh->portName = epicsStrDup(portName);
Expand Down Expand Up @@ -442,21 +449,22 @@ drvAsynPowerPMACPortConfigure(const char *portName,
*/
static const iocshArg drvAsynPowerPMACPortConfigureArg0 = { "port name",iocshArgString};
static const iocshArg drvAsynPowerPMACPortConfigureArg1 = { "host name",iocshArgString};
static const iocshArg drvAsynPowerPMACPortConfigureArg2 = { "username",iocshArgString};
static const iocshArg drvAsynPowerPMACPortConfigureArg3 = { "password",iocshArgString};
static const iocshArg drvAsynPowerPMACPortConfigureArg4 = { "priority",iocshArgInt};
static const iocshArg drvAsynPowerPMACPortConfigureArg5 = { "disable auto-connect",iocshArgInt};
static const iocshArg drvAsynPowerPMACPortConfigureArg6 = { "noProcessEos",iocshArgInt};
static const iocshArg drvAsynPowerPMACPortConfigureArg2 = { "ssh port number",iocshArgInt};
static const iocshArg drvAsynPowerPMACPortConfigureArg3 = { "username",iocshArgString};
static const iocshArg drvAsynPowerPMACPortConfigureArg4 = { "password",iocshArgString};
static const iocshArg drvAsynPowerPMACPortConfigureArg5 = { "priority",iocshArgInt};
static const iocshArg drvAsynPowerPMACPortConfigureArg6 = { "disable auto-connect",iocshArgInt};
static const iocshArg drvAsynPowerPMACPortConfigureArg7 = { "noProcessEos",iocshArgInt};
static const iocshArg *drvAsynPowerPMACPortConfigureArgs[] = {
&drvAsynPowerPMACPortConfigureArg0, &drvAsynPowerPMACPortConfigureArg1,
&drvAsynPowerPMACPortConfigureArg2, &drvAsynPowerPMACPortConfigureArg3,
&drvAsynPowerPMACPortConfigureArg4, &drvAsynPowerPMACPortConfigureArg5,
&drvAsynPowerPMACPortConfigureArg6};
&drvAsynPowerPMACPortConfigureArg6, &drvAsynPowerPMACPortConfigureArg7};
static const iocshFuncDef drvAsynPowerPMACPortConfigureFuncDef =
{"drvAsynPowerPMACPortConfigure",7,drvAsynPowerPMACPortConfigureArgs};
{"drvAsynPowerPMACPortConfigure",8,drvAsynPowerPMACPortConfigureArgs};
static void drvAsynPowerPMACPortConfigureCallFunc(const iocshArgBuf *args)
{
drvAsynPowerPMACPortConfigure(args[0].sval, args[1].sval, args[2].sval, args[3].sval, args[4].ival, args[5].ival, args[6].ival);
drvAsynPowerPMACPortConfigure(args[0].sval, args[1].sval, args[2].ival, args[3].sval, args[4].sval, args[5].ival, args[6].ival, args[7].ival);
}

/*
Expand Down
3 changes: 2 additions & 1 deletion pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
#ifndef DRVASYNPOWERPMACPORT_H
#define DRVASYNPOWERPMACPORT_H

#include <shareLib.h>
#include <shareLib.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

epicsShareFunc int drvAsynPowerPMACPortConfigure(const char *portName,
const char *hostaddress,
unsigned int sshPortNumber,
const char *username,
const char *password,
unsigned int priority,
Expand Down
2 changes: 1 addition & 1 deletion pmacApp/powerPmacAsynPortSrc/interactive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

int main(int argc, char *argv[])
{
SSHDriver *ptr = new SSHDriver("172.23.247.1");
SSHDriver *ptr = new SSHDriver("172.23.247.1",22);
ptr->setUsername("root");
ptr->setPassword("deltatau");
ptr->connectSSH();
Expand Down
9 changes: 5 additions & 4 deletions pmacApp/powerPmacAsynPortSrc/sshDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ void LogComStrPrintEscapedNL(const char *buff, size_t bytes)
* IP address before connecting. Initializes internal variables.
*
* @param host - Host name/IP to attempt a connection with.
* @param port - Port number for ssh connection
*/
SSHDriver::SSHDriver(const char *host)
SSHDriver::SSHDriver(const char *host, unsigned int port)
{
static const char *functionName = "SSHDriver::SSHDriver";
debugPrint("%s : Method called\n", functionName);
Expand All @@ -101,7 +102,7 @@ SSHDriver::SSHDriver(const char *host)
strcpy(password_, "");
// Store the host address
strcpy(host_, host);

sshport_ = port;
error_checking_ = false;
potential_errors_ = 0;
caught_errors_ = 0;
Expand Down Expand Up @@ -190,7 +191,7 @@ SSHDriverStatus SSHDriver::connectSSH()
sock_ = socket(AF_INET, SOCK_STREAM, 0);

sin_.sin_family = AF_INET;
sin_.sin_port = htons(22);
sin_.sin_port = htons(sshport_);
sin_.sin_addr.s_addr = hostaddr;
if (connect(sock_, (struct sockaddr*)(&sin_), sizeof(struct sockaddr_in)) != 0){
debugPrint("%s : socket failed to connect!\n", functionName);
Expand Down Expand Up @@ -291,7 +292,7 @@ SSHDriverStatus SSHDriver::connectSSH()
pfds[0].fd = sock_;
pfds[0].events = POLLIN;
pfds[0].revents = 0;
rc = poll(pfds, numfds, -1);
rc = poll(pfds, numfds, -1);
if (-1 == rc) {
perror("poll");
break;
Expand Down
3 changes: 2 additions & 1 deletion pmacApp/powerPmacAsynPortSrc/sshDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ typedef enum e_SSHDriverStatus
class SSHDriver {

public:
SSHDriver(const char *host);
SSHDriver(const char *host, unsigned int port);
SSHDriverStatus setUsername(const char *username);
SSHDriverStatus setPassword(const char *password);
SSHDriverStatus connectSSH();
Expand All @@ -70,6 +70,7 @@ class SSHDriver {
LIBSSH2_SESSION *session_;
LIBSSH2_CHANNEL *channel_;
char host_[256];
unsigned int sshport_;
char username_[256];
char password_[256];
off_t got_;
Expand Down