Giter Site home page Giter Site logo

Comments (23)

pgrawehr avatar pgrawehr commented on July 28, 2024

What hardware are you running this on? And is there a specific reason why you run your app in a container? This adds additional complexity.

from iot.

m4schini avatar m4schini commented on July 28, 2024

This is running on a custom linux arm iot platform using the azure iot edge runtime. We are using the container runtime from iot edge to deploy our application to the device.

from iot.

pgrawehr avatar pgrawehr commented on July 28, 2024

The callback is known to work on other platforms, so there must be something special about yours, maybe the libgpiod driver is not fully compatible. Have you tried the sysfs driver?

from iot.

m4schini avatar m4schini commented on July 28, 2024

When using the SysFs driver the following exception was thrown when pressing the button connected to the pin:

Unhandled exception. System.IO.IOException: Error while trying to seek in value file.
   at System.Device.Gpio.Drivers.SysFsDriver.WasEventDetected(Int32 pollFileDescriptor, Int32 valueFileDescriptor, Int32& pinNumber, CancellationToken cancellationToken)
   at System.Device.Gpio.Drivers.SysFsDriver.DetectEvents()
   at System.Threading.Thread.StartHelper.Callback(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Thread.StartCallback()

from iot.

krwq avatar krwq commented on July 28, 2024

[Triage] are you forwarding pin related directories to the docker container? what's the exact command line you're using to run your container? (or at least relevant pieces to GPIO) If you can please also share dockerfile

from iot.

krwq avatar krwq commented on July 28, 2024

Here are some basic instructions how to run in the container: https://github.com/dotnet/iot/tree/main/samples/led-blink (last command line is for sysfs)

from iot.

 avatar commented on July 28, 2024

This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment.

from iot.

m4schini avatar m4schini commented on July 28, 2024

are you forwarding pin related directories to the docker container?

Yes, we run the container privileged and we forwarded the directory to the container.

what's the exact command line you're using [...] please also share dockerfile

# final stage/image
FROM mcr.microsoft.com/dotnet/aspnet:7.0.1-alpine3.17
ARG PROJ_NAME
ARG PORT

VOLUME /hostpipe
VOLUME /scripts
VOLUME /libsFromHost

COPY --from=build /testresults /testresults

WORKDIR /app

COPY --from=build /app .
COPY --from=build /app/CBinaries/*.so /app

EXPOSE $PORT
EXPOSE 80

# Copy repository configuration (optional)
COPY alpinehelper/etc/apk/repositories /etc/apk/repositories
# Copy our local repository
COPY alpinehelper/usr/local/repo /usr/local/repo
# Copy keys which we generated previously
COPY alpinehelper/etc/apk/keys /etc/apk/keys

RUN apk --no-cache add libmodbus libmodbus-dev
RUN echo "chmod a+r  /dev/ttySTM3" > ./entrypoint.sh

RUN apk --no-cache add libgpiod-dev gpsd
RUN echo "gpsd /dev/ttySTM3 -F /var/run/gpsd.sock" >> ./entrypoint.sh
RUN echo "./${PROJ_NAME}" >> ./entrypoint.sh

RUN cat ./entrypoint.sh

RUN chmod 777 ./entrypoint.sh
ENTRYPOINT ./entrypoint.sh

from iot.

joperezr avatar joperezr commented on July 28, 2024

Thanks for the Dockerfile. We would also need the docker run command to see how are you volume-mounting the necessary files for sysfs driver to work.

from iot.

m4schini avatar m4schini commented on July 28, 2024

We are using the azure iot edge runtime to deploy and start our containers. To do that we don't provide a command but a manifest where we define modules. We tried three different things, I will list the attempts below:

Attempt 1: only running privileged
          "module": {
            "startupOrder": 1,
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "",
              "createOptions": {
                "HostConfig": {
                  "LogConfig": {
                    "Type": "json-file",
                    "Config": {
                      "max-size": "5m",
                      "max-file": "1"
                    }
                  },
                  "Privileged": true,
                  "Binds": [
                    "/dev/ttyWifi:/dev/ttyWifi",
                    "/dev/ttyRS485:/dev/ttyRS485",
                    "/sys:/sys"
                  ],
                  "IpcMode": "shareable",
                  "CapAdd": [
                    "NET_ADMIN"
                  ],
                  "Devices": [
                    {
                      "PathOnHost": "/dev/ttyWifi",
                      "PathInContainer": "/dev/ttyWifi",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev/ttyRS485",
                      "PathInContainer": "/dev/ttyRS485",
                      "CgroupPermissions": "rwm"
                    }
                  ],
                  "Mounts": [
                    {
                      "Source": "/lib",
                      "Target": "/libsFromHost",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/mnt/pData/scripts",
                      "Target": "/scripts",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/sys",
                      "Target": "/sys",
                      "Type": "bind",
                      "ReadOnly": false
                    }
                  ],
                  "PortBindings": {
                    "4444/tcp": [
                      {
                        "HostPort": "4444"
                      }
                    ],
                    "80/tcp": [
                      {
                        "HostPort": "80"
                      }
                    ]
                  }
                }
              }
            },
Attempt 2: Binding /sys
          "module": {
            "startupOrder": 1,
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "",
              "createOptions": {
                "HostConfig": {
                  "LogConfig": {
                    "Type": "json-file",
                    "Config": {
                      "max-size": "5m",
                      "max-file": "1"
                    }
                  },
                  "Privileged": true,
                  "Binds": [
                    "/dev/ttyWifi:/dev/ttyWifi",
                    "/dev/ttyRS485:/dev/ttyRS485",
                    "/sys:/sys"
                  ],
                  "IpcMode": "shareable",
                  "CapAdd": [
                    "NET_ADMIN"
                  ],
                  "Devices": [
                    {
                      "PathOnHost": "/dev/ttyWifi",
                      "PathInContainer": "/dev/ttyWifi",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev/ttyRS485",
                      "PathInContainer": "/dev/ttyRS485",
                      "CgroupPermissions": "rwm"
                    }
                  ],
                  "Mounts": [
                    {
                      "Source": "/lib",
                      "Target": "/libsFromHost",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/mnt/pData/scripts",
                      "Target": "/scripts",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/sys",
                      "Target": "/sys",
                      "Type": "bind",
                      "ReadOnly": false
                    }
                  ],
                  "PortBindings": {
                    "4444/tcp": [
                      {
                        "HostPort": "4444"
                      }
                    ],
                    "80/tcp": [
                      {
                        "HostPort": "80"
                      }
                    ]
                  }
                }
              }
            },
Attempt 3: Binding gpiochip
"module": {
            "startupOrder": 1,
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "",
              "createOptions": {
                "HostConfig": {
                  "LogConfig": {
                    "Type": "json-file",
                    "Config": {
                      "max-size": "5m",
                      "max-file": "1"
                    }
                  },
                  "Privileged": true,
                  "Binds": [
                    "/dev/ttyWifi:/dev/ttyWifi",
                    "/dev/ttyRS485:/dev/ttyRS485",
                    "/dev/gpiochip2:/dev/gpiochip2",
                    "/dev/mem:/dev/mem"
                  ],
                  "IpcMode": "shareable",
                  "CapAdd": [
                    "NET_ADMIN"
                  ],
                  "Devices": [
                    {
                      "PathOnHost": "/dev/ttyWifi",
                      "PathInContainer": "/dev/ttyWifi",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev/ttyRS485",
                      "PathInContainer": "/dev/ttyRS485",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev/gpiochip2",
                      "PathInContainer": "/dev/gpiochip2",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev/mem",
                      "PathInContainer": "/dev/mem",
                      "CgroupPermissions": "rwm"
                    }
                  ],
                  "Mounts": [
                    {
                      "Source": "/lib",
                      "Target": "/libsFromHost",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/mnt/pData/scripts",
                      "Target": "/scripts",
                      "Type": "bind",
                      "ReadOnly": false
                    }
                  ],
                  "PortBindings": {
                    "4444/tcp": [
                      {
                        "HostPort": "4444"
                      }
                    ],
                    "80/tcp": [
                      {
                        "HostPort": "80"
                      }
                    ]
                  }
                }
              }
            },

None of these attempts worked out.

from iot.

Ellerbach avatar Ellerbach commented on July 28, 2024

Thanks @m4schini
Can you try priviledged with /dev to /dev and /sys to /sys binding. That should definitely work.
Then, you can restrict, depending on the GPIO you're using. They will bind differently if sysfs or libgpio, etc.
Check out the source code here for the driver you need (assuming you have the proper lib installed into the container): https://github.com/dotnet/iot/tree/main/src/System.Device.Gpio/System/Device/Gpio

from iot.

m4schini avatar m4schini commented on July 28, 2024

We tried it as you described and the behavior for both Sysfs and libgpio is unchanged.

For reference the manifests we used:

Deployment manifest (/sys as device)
"module": {
            "startupOrder": 1,
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "",
              "createOptions": {
                "HostConfig": {
                  "LogConfig": {
                    "Type": "json-file",
                    "Config": {
                      "max-size": "5m",
                      "max-file": "1"
                    }
                  },
                  "Privileged": true,
                  "Binds": [
                    "/dev/ttyWifi:/dev/ttyWifi",
                    "/dev/ttyRS485:/dev/ttyRS485",
                    "/dev:/dev",
                    "/sys:/sys"
                  ],
                  "IpcMode": "shareable",
                  "CapAdd": [
                    "NET_ADMIN"
                  ],
                  "Devices": [
                    {
                      "PathOnHost": "/dev/ttyWifi",
                      "PathInContainer": "/dev/ttyWifi",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev/ttyRS485",
                      "PathInContainer": "/dev/ttyRS485",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev",
                      "PathInContainer": "/dev",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "Source": "/sys",
                      "Target": "/sys",
                      "CgroupPermissions": "rwm"
                    }
                  ],
                  "Mounts": [
                    {
                      "Source": "/lib",
                      "Target": "/libsFromHost",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/mnt/pData/execpipe",
                      "Target": "/hostpipe",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/mnt/pData/scripts",
                      "Target": "/scripts",
                      "Type": "bind",
                      "ReadOnly": false
                    }
                  ],
                  "PortBindings": {
                    "4444/tcp": [
                      {
                        "HostPort": "4444"
                      }
                    ],
                    "80/tcp": [
                      {
                        "HostPort": "80"
                      }
                    ]
                  }
                }
              }
            },
Deployment manifest (/sys not as device)
"module": {
            "startupOrder": 1,
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "",
              "createOptions": {
                "HostConfig": {
                  "LogConfig": {
                    "Type": "json-file",
                    "Config": {
                      "max-size": "5m",
                      "max-file": "1"
                    }
                  },
                  "Privileged": true,
                  "Binds": [
                    "/dev/ttyWifi:/dev/ttyWifi",
                    "/dev/ttyRS485:/dev/ttyRS485",
                    "/dev:/dev",
                    "/sys:/sys"
                  ],
                  "IpcMode": "shareable",
                  "CapAdd": [
                    "NET_ADMIN"
                  ],
                  "Devices": [
                    {
                      "PathOnHost": "/dev/ttyWifi",
                      "PathInContainer": "/dev/ttyWifi",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev/ttyRS485",
                      "PathInContainer": "/dev/ttyRS485",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev",
                      "PathInContainer": "/dev",
                      "CgroupPermissions": "rwm"
                    }
                  ],
                  "Mounts": [
                    {
                      "Source": "/lib",
                      "Target": "/libsFromHost",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/mnt/pData/execpipe",
                      "Target": "/hostpipe",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/mnt/pData/scripts",
                      "Target": "/scripts",
                      "Type": "bind",
                      "ReadOnly": false
                    }
                  ],
                  "PortBindings": {
                    "4444/tcp": [
                      {
                        "HostPort": "4444"
                      }
                    ],
                    "80/tcp": [
                      {
                        "HostPort": "80"
                      }
                    ]
                  }
                }
              }
            },

In addition to that we also tried to do the same with a slightly different manifest. This time instead of "Binds" we used "Mounts" with bind type:

Deployment manifest
"module": {
            "startupOrder": 1,
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "settings": {
              "image": "",
              "createOptions": {
                "HostConfig": {
                  "LogConfig": {
                    "Type": "json-file",
                    "Config": {
                      "max-size": "5m",
                      "max-file": "1"
                    }
                  },
                  "Privileged": true,
                  "Binds": [
                    "/dev/ttyWifi:/dev/ttyWifi",
                    "/dev/ttyRS485:/dev/ttyRS485"
                  ],
                  "IpcMode": "shareable",
                  "CapAdd": [
                    "NET_ADMIN"
                  ],
                  "Devices": [
                    {
                      "PathOnHost": "/dev/ttyWifi",
                      "PathInContainer": "/dev/ttyWifi",
                      "CgroupPermissions": "rwm"
                    },
                    {
                      "PathOnHost": "/dev/ttyRS485",
                      "PathInContainer": "/dev/ttyRS485",
                      "CgroupPermissions": "rwm"
                    }
                  ],
                  "Mounts": [
                    {
                      "Source": "/lib",
                      "Target": "/libsFromHost",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/mnt/pData/execpipe",
                      "Target": "/hostpipe",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/mnt/pData/scripts",
                      "Target": "/scripts",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "PathOnHost": "/dev",
                      "PathInContainer": "/dev",
                      "Type": "bind",
                      "ReadOnly": false
                    },
                    {
                      "Source": "/sys",
                      "Target": "/sys",
                      "Type": "bind",
                      "ReadOnly": false
                    }
                  ],
                  "PortBindings": {
                    "4444/tcp": [
                      {
                        "HostPort": "4444"
                      }
                    ],
                    "80/tcp": [
                      {
                        "HostPort": "80"
                      }
                    ]
                  }
                }
              }
            },

And got the following error in the iot edge agent (which is starting the container on the device)

System.AggregateException: One or more errors occurred. (Error calling Create module module: runtime operation error: create module "module")
 ---> Microsoft.Azure.Devices.Edge.Agent.Edgelet.EdgeletCommunicationException- Message:Error calling Create module module: runtime operation error: create module "module", StatusCode:400, at:   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.Version_2022_08_03.ModuleManagementHttpClient.HandleException(Exception exception, String operation) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2022_08_03/ModuleManagementHttpClient.cs:line 232
   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.Versioning.ModuleManagementHttpClientVersioned.Execute[T](Func`1 func, String operation) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/versioning/ModuleManagementHttpClientVersioned.cs:line 171
   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.Version_2022_08_03.ModuleManagementHttpClient.CreateModuleAsync(ModuleSpec moduleSpec) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2022_08_03/ModuleManagementHttpClient.cs:line 102
   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.ModuleManagementHttpClient.<>c__DisplayClass26_0.<<Throttle>b__0>d.MoveNext() in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/ModuleManagementHttpClient.cs:line 145
--- End of stack trace from previous location ---
   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.ModuleManagementHttpClient.Throttle[T](Func`1 identityOperation) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/ModuleManagementHttpClient.cs:line 164
   at Microsoft.Azure.Devices.Edge.Agent.Core.Commands.GroupCommand.ExecuteAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/commands/GroupCommand.cs:line 35
   at Microsoft.Azure.Devices.Edge.Agent.Core.LoggingCommandFactory.LoggingCommand.ExecuteAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/LoggingCommandFactory.cs:line 69
   at Microsoft.Azure.Devices.Edge.Agent.Core.Commands.GroupCommand.ExecuteAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/commands/GroupCommand.cs:line 35
   at Microsoft.Azure.Devices.Edge.Agent.Core.LoggingCommandFactory.LoggingCommand.ExecuteAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/LoggingCommandFactory.cs:line 69
   at Microsoft.Azure.Devices.Edge.Agent.Core.PlanRunner.OrderedRetryPlanRunner.ExecuteAsync(Int64 deploymentId, Plan plan, CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/planrunner/OrdererdRetryPlanRunner.cs:line 91
   --- End of inner exception stack trace ---
   at Microsoft.Azure.Devices.Edge.Agent.Core.PlanRunner.OrderedRetryPlanRunner.<>c.<ExecuteAsync>b__7_0(List`1 f) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/planrunner/OrdererdRetryPlanRunner.cs:line 129
   at Microsoft.Azure.Devices.Edge.Agent.Core.PlanRunner.OrderedRetryPlanRunner.ExecuteAsync(Int64 deploymentId, Plan plan, CancellationToken token)
   at Microsoft.Azure.Devices.Edge.Agent.Core.Agent.ReconcileAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/Agent.cs:line 208
<4> 2023-09-21 08:58:23.738 +00:00 [WRN] - Reconcile failed because of the an exception
System.AggregateException: One or more errors occurred. (Error calling Create module module: runtime operation error: create module "module")
 ---> Microsoft.Azure.Devices.Edge.Agent.Edgelet.EdgeletCommunicationException- Message:Error calling Create module module: runtime operation error: create module "module", StatusCode:400, at:   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.Version_2022_08_03.ModuleManagementHttpClient.HandleException(Exception exception, String operation) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2022_08_03/ModuleManagementHttpClient.cs:line 232
   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.Versioning.ModuleManagementHttpClientVersioned.Execute[T](Func`1 func, String operation) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/versioning/ModuleManagementHttpClientVersioned.cs:line 171
   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.Version_2022_08_03.ModuleManagementHttpClient.CreateModuleAsync(ModuleSpec moduleSpec) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2022_08_03/ModuleManagementHttpClient.cs:line 102
   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.ModuleManagementHttpClient.<>c__DisplayClass26_0.<<Throttle>b__0>d.MoveNext() in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/ModuleManagementHttpClient.cs:line 145
--- End of stack trace from previous location ---
   at Microsoft.Azure.Devices.Edge.Agent.Edgelet.ModuleManagementHttpClient.Throttle[T](Func`1 identityOperation) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/ModuleManagementHttpClient.cs:line 164
   at Microsoft.Azure.Devices.Edge.Agent.Core.Commands.GroupCommand.ExecuteAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/commands/GroupCommand.cs:line 35
   at Microsoft.Azure.Devices.Edge.Agent.Core.LoggingCommandFactory.LoggingCommand.ExecuteAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/LoggingCommandFactory.cs:line 69
   at Microsoft.Azure.Devices.Edge.Agent.Core.Commands.GroupCommand.ExecuteAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/commands/GroupCommand.cs:line 35
   at Microsoft.Azure.Devices.Edge.Agent.Core.LoggingCommandFactory.LoggingCommand.ExecuteAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/LoggingCommandFactory.cs:line 69
   at Microsoft.Azure.Devices.Edge.Agent.Core.PlanRunner.OrderedRetryPlanRunner.ExecuteAsync(Int64 deploymentId, Plan plan, CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/planrunner/OrdererdRetryPlanRunner.cs:line 91
   --- End of inner exception stack trace ---
   at Microsoft.Azure.Devices.Edge.Agent.Core.PlanRunner.OrderedRetryPlanRunner.<>c.<ExecuteAsync>b__7_0(List`1 f) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/planrunner/OrdererdRetryPlanRunner.cs:line 129
   at Microsoft.Azure.Devices.Edge.Agent.Core.PlanRunner.OrderedRetryPlanRunner.ExecuteAsync(Int64 deploymentId, Plan plan, CancellationToken token)
   at Microsoft.Azure.Devices.Edge.Agent.Core.Agent.ReconcileAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/Agent.cs:line 208
   at Microsoft.Azure.Devices.Edge.Agent.Core.Agent.ReconcileAsync(CancellationToken token) in /mnt/vss/_work/1/s/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/Agent.cs:line 208

Check out the source code here for the driver you need

We use, depending on what we are testing, either SysFsDriver.cs or LibGpiodDriver.cs.

(assuming you have the proper lib installed into the container)

We confirmed that both work inside the container with the usual command line utilities.

from iot.

joperezr avatar joperezr commented on July 28, 2024

[Triage] - Sorry @m4schini I know we suggested above to try sysfs but I somehow missed the part you saying that you were running on iot edge. We believe that this is a limitation of azure iot edge where you can't really volume mount the paths you need in order for sysfs driver to work. All that said, in general we usually prefer libgpiod driver as that is usually much more accurate, so I think it's worth going back to that versio instead and figure out what's wrong there. Is it just eventing that is not working for you? What I mean by this is, if you write to a pin which is connected to another pin, do you see the values changing?

from iot.

m4schini avatar m4schini commented on July 28, 2024

Yes we also expect the problem to be Eventing related because of the behavior we observed (inside the container):

  • We can write and read pin values in C# code with the libgpiod driver
  • We can write and read pin values with the gpiolib command line tools
  • We can also observe pin value changes via gpiomon:
gpiomon 2 12
event:  RISING EDGE offset: 12 timestamp: [      54.261767639]
event: FALLING EDGE offset: 12 timestamp: [      54.425665514]

from iot.

m4schini avatar m4schini commented on July 28, 2024

I'm going on Vacation, my collegue (@ignaciocaramba) will be taking over this issue from our side.

from iot.

ignaciocaramba avatar ignaciocaramba commented on July 28, 2024

As a side note:
If we comment out this section in the SysFsDriver "it works" (we get events on change):

private unsafe bool WasEventDetected(int pollFileDescriptor, int valueFileDescriptor, out int pinNumber, CancellationToken cancellationToken)
    {
        char buf;
        IntPtr bufPtr = new IntPtr(&buf);
        pinNumber = -1;

        while (!cancellationToken.IsCancellationRequested)
        {
            // Wait until something happens
            int waitResult = CustomInterop.CustomInterop.epoll_wait(pollFileDescriptor, out epoll_event events, 1, PollingTimeout);
            if (waitResult == -1)
            {
                var errorCode = Marshal.GetLastWin32Error();
                if (errorCode == ERROR_CODE_EINTR)
                {
                    // ignore Interrupted system call error and retry
                    continue;
                }

                throw new IOException($"Error while waiting for pin interrupts. (ErrorCode={errorCode})");
            }

            if (waitResult > 0)
            {
                pinNumber = events.data.pinNumber;

                /* WE COMMENTED OUT THIS SECTION
                // This entire section is probably not necessary, but this seems to be hard to validate.
                // See https://github.com/dotnet/iot/pull/914#discussion_r389924106 and issue #1024.
                if (valueFileDescriptor == -1)
                {
                    // valueFileDescriptor will be -1 when using the callback eventing. For WaitForEvent, the value will be set.
                    valueFileDescriptor = _devicePins[pinNumber].FileDescriptor;
                }

                int lseekResult = CustomInterop.CustomInterop.lseek(valueFileDescriptor, 0, SeekFlags.SEEK_SET);
                if (lseekResult == -1)
                {
                    throw new IOException("Error while trying to seek in value file.");
                }

                int readResult = CustomInterop.CustomInterop.read(valueFileDescriptor, bufPtr, 1);
                if (readResult != 1)
                {
                    throw new IOException("Error while trying to read value file.");
                }
                */

                return true;
            }
        }

        return false;
    }

from iot.

pgrawehr avatar pgrawehr commented on July 28, 2024

That's interesting, in particular due to the comment there. Can you check what the value of valueFileDescriptor is before and after the first "if" in that section?

from iot.

ignaciocaramba avatar ignaciocaramba commented on July 28, 2024

@pgrawehr
before: -1
after: 329

from iot.

ignaciocaramba avatar ignaciocaramba commented on July 28, 2024

@pgrawehr any updates?

from iot.

pgrawehr avatar pgrawehr commented on July 28, 2024

@ignaciocaramba Sorry, I didn't have time to look into this. Since it appears to be working if you comment out that block of code (whose existing comment already says that it's questionable), we could verify whether removing that would cause the other boards to break. Can you submit a PR with that piece of code commented out? That would trigger the CI run and we would see whether it directly causes any issues. CI is running a bunch of GPIO tests on actual hardware.

from iot.

ignaciocaramba avatar ignaciocaramba commented on July 28, 2024

@pgrawehr Pr created and All tests have passed

from iot.

ignaciocaramba avatar ignaciocaramba commented on July 28, 2024

The pr fixes the issue with the SysfsDriver, but our initial problem is not fixed: if instead of using Sysfs we use LibGpiod when registering a Callback via RegisterCallbackForPinValueChangedEvent and changing the value of the gpio pin, the callback is not being called.

Also, is there a problem to use SysfsDriver instead of LibgpiodDriver for listening to button events?

from iot.

pgrawehr avatar pgrawehr commented on July 28, 2024

@ignaciocaramba You seem to have some special hardware there, and it was kind of a coincidence that it could be so easily fixed for Sysfs. When it doesn't work with libgpiod the problem is probably in the library or the hardware and there's likely nothing we can do on our side.

SysFs is generally much slower than libgpiod. If you use this only for buttons, the impact will be negligible. If you need to handle events in the Kilohertz range, then sysfs might not be fast enough and you will loose events.

from iot.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.