diff --git a/docs/powerpmac_simulator_setup.md b/docs/powerpmac_simulator_setup.md new file mode 100644 index 00000000..16b6b78c --- /dev/null +++ b/docs/powerpmac_simulator_setup.md @@ -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@ +``` + +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. \ No newline at end of file diff --git a/etc/builder.py b/etc/builder.py index 71eadfdc..6342e503 100644 --- a/etc/builder.py +++ b/etc/builder.py @@ -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 @@ -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), diff --git a/etc/makeIocs/lab-ppmac.xml b/etc/makeIocs/lab-ppmac.xml index 679cc83b..99d89e57 100644 --- a/etc/makeIocs/lab-ppmac.xml +++ b/etc/makeIocs/lab-ppmac.xml @@ -1,7 +1,7 @@ - + diff --git a/etc/makeIocs/powerPMAC.xml b/etc/makeIocs/powerPMAC.xml index f525bf43..e0b7dd95 100644 --- a/etc/makeIocs/powerPMAC.xml +++ b/etc/makeIocs/powerPMAC.xml @@ -1,6 +1,6 @@ - + diff --git a/pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.cpp b/pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.cpp index b1e9516a..45ff2dbb 100644 --- a/pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.cpp +++ b/pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.cpp @@ -36,6 +36,7 @@ typedef struct { asynUser *pasynUser; /* Not currently used */ char *SSHDeviceName; char *SSHHostName; + unsigned int SSHPortNumber; char *SSHUserName; char *SSHPassword; char *portName; @@ -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); @@ -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; @@ -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, @@ -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; @@ -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); @@ -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); } /* diff --git a/pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.h b/pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.h index 778340bf..ae23b0ea 100644 --- a/pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.h +++ b/pmacApp/powerPmacAsynPortSrc/drvAsynPowerPMACPort.h @@ -4,7 +4,7 @@ #ifndef DRVASYNPOWERPMACPORT_H #define DRVASYNPOWERPMACPORT_H -#include +#include #ifdef __cplusplus extern "C" { @@ -12,6 +12,7 @@ extern "C" { epicsShareFunc int drvAsynPowerPMACPortConfigure(const char *portName, const char *hostaddress, + unsigned int sshPortNumber, const char *username, const char *password, unsigned int priority, diff --git a/pmacApp/powerPmacAsynPortSrc/interactive.cpp b/pmacApp/powerPmacAsynPortSrc/interactive.cpp index 34367a4a..dc0b6afe 100755 --- a/pmacApp/powerPmacAsynPortSrc/interactive.cpp +++ b/pmacApp/powerPmacAsynPortSrc/interactive.cpp @@ -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(); diff --git a/pmacApp/powerPmacAsynPortSrc/sshDriver.cpp b/pmacApp/powerPmacAsynPortSrc/sshDriver.cpp index 42a960eb..440473df 100755 --- a/pmacApp/powerPmacAsynPortSrc/sshDriver.cpp +++ b/pmacApp/powerPmacAsynPortSrc/sshDriver.cpp @@ -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); @@ -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; @@ -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); @@ -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; diff --git a/pmacApp/powerPmacAsynPortSrc/sshDriver.h b/pmacApp/powerPmacAsynPortSrc/sshDriver.h index 5a87ea36..538b4d83 100644 --- a/pmacApp/powerPmacAsynPortSrc/sshDriver.h +++ b/pmacApp/powerPmacAsynPortSrc/sshDriver.h @@ -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(); @@ -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_;