Drivers

Drivers are the services that the av-api calls to talk to physical AV devices. We write/use libraries that implement one of the interfaces in this package - which interface they implement depends on the type of device the driver is written for.

Subdirectories of this package are all of our BYU-specific driver servers, which are compiled into docker containers based on the dockerfile (and the dockerfile-arm for arm containers).

Writing a Driver

  1. Create a new repo, titled with the control protocol or vendor -driver.

    1. Use the github provided Go .gitignore.

    2. Repos from BYU OIT AV should use the Apache 2.0 License

  2. Clone your repo by running git clone git@github.com:<org/repo>.git

    All new repos should use go mod. Make sure to clone your repo outside of your $GOPATH.
  3. Initialize go mod by running go mod init <github.com/org/repo> in your newly cloned repo.

  4. In a new file, create a struct in your new package that will implement the appropriate interface. Its fields should have data required to use the driver.

    Each instantiation of your struct should semantically represent a specific device (IE a single projector) and as such should contain all of the information required to control that device
    package adcp (1)
    
    type Projector struct {
    	Address  string (2)
    	Username string (2)
    	Password string (2)
    }
    1 A driver library should typically have only one package
    2 Not required, just an example
  5. Implement all of the required functions in the matching interface found in this package. For example, to make a projector driver, you would probably want to implement the interface found in display.go.

    func (p *Projector) GetPower(ctx context.Context) (string, error) { (1)
    }
    1 Confused with context? These articles are a great place to start: 1, 2, 3
    Make sure that your driver library has good test code to ensure future changes don’t break things. 😊
  6. Once a working version of your library is ready, release a v1.0.0 version of it. For future releases, use semantic versioning to denote changes.

    Err on the side of caution here. It’s ok to stay at V0.X for a while as things stabilize. Once you go V1, things will have to follow semantic far more strictly.
$ git tag -a "v1.0.0"
$ git push --tags

Creating a Driver Server

Once you have finished a library, or want to use one that implements one of the driver interfaces, you create create a driver server.

  1. Create a subdirectory in this one with the name of your driver server. Usually, this should match the driver name, without the -driver suffix.

  2. In your new directory, initalize go mod by running go mod init github.com/byuoitav/drivers/<folder name>

    In this case, go mod is used to reliably import the correct version of external libraries, and not for exporting your package.
  3. Add the dockerfiles for both linux and arm to the directory

  4. TODO anything else https://github.com/bwinterton needs to build these (makefiles, etc.)

  5. Create a server.go file. This is where all of your driver server’s code should go.

    This will be changing shortly to represent new decisions. (TODO)
package main (1)

// imports

func main() { (1)
    var port int
    // variable declarations

    pflag.IntVarP(&port, "port", "p", 80, "port to run the server on") (2)
    // other flags

    pflag.Parse() (3)

    // create a net.Listener to run the server on
    addr := fmt.Sprintf(":%d", port)
    lis, err := net.Listen("tcp", addr)
    if err != nil {
        // handle err
    }

    // import driver library
    display := &adcp.Projector{} (4)

    // create server
    server := drivers.CreateDisplayServer(display) (5)
    if err = server.Serve(lis); err != nil {
        // handle err
    }
}
1 Must be in package main with a main() function. This is where your driver server will start.
2 The port to run our servers will be passed in as part of the dockerfile.
3 We use the pflag library for POSIX style flags.
4 The variable, package, and struct name will change depending on the driver you are importing.
5 Use the correct Create…​Server() function for the interface your driver implements.