diff --git a/mappers/gpio-atlas200/Dockerfile b/mappers/gpio-atlas200/Dockerfile new file mode 100644 index 00000000..7201c0a8 --- /dev/null +++ b/mappers/gpio-atlas200/Dockerfile @@ -0,0 +1,11 @@ +FROM ubuntu:20.04 +WORKDIR /usr/local/bin +COPY ./res /usr/local/res +COPY ./bin /usr/local/bin +#RUN echo "HwHiAiUser:x:1000:1000::/home/HwHiAiUser:" >> /etc/passwd ; \ +#echo "HwHiAiUser:x:1024:" >> /etc/group ; \ +#echo "HwHiAiUser:!:17795:0:99999:7:::" >> /etc/shadow ; \ +#chown -R 1000:1000 /usr/local/bin; \ +#chown -R 1000:1000 /usr/local/res; +USER 0 +ENTRYPOINT ["./gpio","--v","4"] diff --git a/mappers/gpio-atlas200/Makefile b/mappers/gpio-atlas200/Makefile new file mode 100644 index 00000000..d59c981e --- /dev/null +++ b/mappers/gpio-atlas200/Makefile @@ -0,0 +1,36 @@ +SHELL := /bin/bash + +curr_dir := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +rest_args := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS)) +$(eval $(rest_args):;@:) + +help: + # + # Usage: + # make template : create a mapper based on a template. + # make mapper {mapper-name} : execute mapper building process. + # make all : execute building process to all mappers. + # + # Actions: + # - mod, m : download code dependencies. + # - lint, l : verify code via go fmt and `golangci-lint`. + # - build, b : compile code. + # - package, p : package docker image. + # - test, t : run unit tests. + # - clean, c : clean output binary. + # + # Parameters: + # ARM : true or undefined + # ARM64 : true or undefined + # + # Example: + # - make mapper gpio ARM64=true : execute `build` "gpio" mapper for ARM64. + # - make mapper gpio test : execute `test` "gpio" mapper. + @echo + +make_rules := $(shell ls $(curr_dir)/hack/make-rules | sed 's/.sh//g') +$(make_rules): + @$(curr_dir)/hack/make-rules/$@.sh $(rest_args) + +.DEFAULT_GOAL := help +.PHONY: $(make_rules) build test package diff --git a/mappers/gpio-atlas200/cmd/main.go b/mappers/gpio-atlas200/cmd/main.go new file mode 100644 index 00000000..13d8ad0f --- /dev/null +++ b/mappers/gpio-atlas200/cmd/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "github.com/kubeedge/mappers-go/mapper-sdk-go/pkg/service" + "github.com/kubeedge/mappers-go/mappers/gpio-atlas200/driver" +) + +// main gpio device program entry +func main() { + gpio := &driver.GPIO{} + service.Bootstrap("GPIO", gpio) +} diff --git a/mappers/gpio-atlas200/crd_example/gpio-deployment.yaml b/mappers/gpio-atlas200/crd_example/gpio-deployment.yaml new file mode 100644 index 00000000..52b87967 --- /dev/null +++ b/mappers/gpio-atlas200/crd_example/gpio-deployment.yaml @@ -0,0 +1,60 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gpio-deploy-edge-line +spec: + replicas: 1 + selector: + matchLabels: + app: gpio-line1 + template: + metadata: + labels: + app: gpio-line1 + spec: + hostNetwork: true + nodeSelector: + kubernetes.io/hostname: edge-a200-00 + containers: + - name: gpio-container + image: gpio-mapper-arm64:v1.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 1215 + hostPort: 1215 + hostIP: 0.0.0.0 + securityContext: + privileged: true + volumeMounts: + - name: config-volume + mountPath: /opt/kubeedge/ + - name: gpio0-direction + mountPath: /sys/class/gpio/gpio504/direction + - name: gpio1-direction + mountPath: /sys/class/gpio/gpio444/direction + - name: gpio0-value + mountPath: /sys/class/gpio/gpio504/value + - name: gpio1-value + mountPath: /sys/class/gpio/gpio444/value + - name: i2c-path + mountPath: /dev/i2c-1 + volumes: + - name: config-volume + configMap: + name: device-profile-config-edge-a200-00 + - name: gpio0-direction + hostPath: + path: /sys/class/gpio/gpio504/direction + - name: gpio1-direction + hostPath: + path: /sys/class/gpio/gpio444/direction + - name: gpio0-value + hostPath: + path: /sys/class/gpio/gpio504/value + - name: gpio1-value + hostPath: + path: /sys/class/gpio/gpio444/value + - name: i2c-path + hostPath: + path: /dev/i2c-1 + restartPolicy: Always diff --git a/mappers/gpio-atlas200/crd_example/gpio-device-instance.yaml b/mappers/gpio-atlas200/crd_example/gpio-device-instance.yaml new file mode 100644 index 00000000..8f544d85 --- /dev/null +++ b/mappers/gpio-atlas200/crd_example/gpio-device-instance.yaml @@ -0,0 +1,78 @@ +apiVersion: devices.kubeedge.io/v1alpha2 +kind: Device +metadata: + name: led-instance-01 + labels: + model: led-model +spec: + deviceModelRef: + name: led-model + protocol: + customizedProtocol: + protocolName: GPIO + nodeSelector: + nodeSelectorTerms: + - matchExpressions: + - key: '' + operator: In + values: + - edge-a200-00 #pls give your edge node name + propertyVisitors: + - propertyName: red-power-status + collectCycle: 10000000000 #Mapper 从设备收集数据的频率 + reportCycle: 1000000000 #Mapper 报告数据的频率 + customizedProtocol: + protocolName: GPIO + configData: + pin: 0 #pls give your red light's Pin + - propertyName: green-power-status + collectCycle: 10000000000 #Mapper 从设备收集数据的频率 + reportCycle: 1000000000 #Mapper 报告数据的频率 + customizedProtocol: + protocolName: GPIO + configData: + pin: 1 #pls give your green light's Pin + - propertyName: yellow-power-status + collectCycle: 10000000000 #Mapper 从设备收集数据的频率 + reportCycle: 1000000000 #Mapper 报告数据的频率 + customizedProtocol: + protocolName: GPIO + configData: + pin: 3 #pls give your yellow light's Pin, pin 2 is not vaild for atlas200dk + +status: + twins: + - propertyName: red-power-status + reported: + metadata: + timestamp: '1550049403598' + type: string + value: "OFF" + desired: + metadata: + timestamp: '1550049403598' + type: string + value: "OFF" + - propertyName: green-power-status + reported: + metadata: + timestamp: '1550049403598' + type: string + value: "OFF" + desired: + metadata: + timestamp: '1550049403598' + type: string + value: "ON" + - propertyName: yellow-power-status + reported: + metadata: + timestamp: '1550049403598' + type: string + value: "OFF" + desired: + metadata: + timestamp: '1550049403598' + type: string + value: "OFF" + diff --git a/mappers/gpio-atlas200/crd_example/gpio-device-model.yaml b/mappers/gpio-atlas200/crd_example/gpio-device-model.yaml new file mode 100644 index 00000000..60594b23 --- /dev/null +++ b/mappers/gpio-atlas200/crd_example/gpio-device-model.yaml @@ -0,0 +1,26 @@ +apiVersion: devices.kubeedge.io/v1alpha2 +kind: DeviceModel +metadata: + name: led-model + namespace: default +spec: + properties: + - name: red-power-status + description: red + type: + string: + accessMode: ReadWrite + defaultValue: "OFF" + - name: green-power-status + description: green + type: + string: + accessMode: ReadWrite + defaultValue: "OFF" + - name: yellow-power-status + description: yellow + type: + string: + accessMode: ReadWrite + defaultValue: "ON" + \ No newline at end of file diff --git a/mappers/gpio-atlas200/driver/driver.go b/mappers/gpio-atlas200/driver/driver.go new file mode 100644 index 00000000..4f2f1329 --- /dev/null +++ b/mappers/gpio-atlas200/driver/driver.go @@ -0,0 +1,131 @@ +package driver + +import ( + "encoding/json" + "fmt" + "strings" + "sync" +) + +// GPIOProtocolConfig is the protocol config structure. +type GPIOProtocolConfig struct { + ProtocolName string `json:"protocolName"` + ProtocolConfigData `json:"configData"` +} +// ProtocolConfigData is the protocol config data structure. +type ProtocolConfigData struct { +} + +// GPIOProtocolCommonConfig is the protocol common config structure. +type GPIOProtocolCommonConfig struct { + CommonCustomizedValues `json:"customizedValues"` +} + +// CommonCustomizedValues is the customized values structure. +type CommonCustomizedValues struct { +} +// GPIOVisitorConfig is the visitor config structure. +type GPIOVisitorConfig struct { + ProtocolName string `json:"protocolName"` + VisitorConfigData `json:"configData"` +} + +// VisitorConfigData is the visitor config data structure. +type VisitorConfigData struct { + Pin int `json:"pin"` +} + +// GPIO Realize the structure of random number +type GPIO struct { + mutex sync.Mutex + protocolConfig GPIOProtocolConfig + protocolCommonConfig GPIOProtocolCommonConfig + visitorConfig GPIOVisitorConfig +} + +// InitDevice Sth that need to do in the first +// If you need mount a persistent connection, you should provide parameters in configmap's protocolCommon. +// and handle these parameters in the following function +func (d *GPIO) InitDevice(protocolCommon []byte) (err error) { + if protocolCommon != nil { + if err = json.Unmarshal(protocolCommon, &d.protocolCommonConfig); err != nil { + fmt.Printf("Unmarshal ProtocolCommonConfig error: %v\n", err) + return err + } + } + fmt.Println("GPIO devices do not need to be initialized") + return nil +} + +// SetConfig Parse the configmap's raw json message +func (d *GPIO) SetConfig(protocolCommon, visitor, protocol []byte) (pin int, err error) { + d.mutex.Lock() + defer d.mutex.Unlock() + if protocolCommon != nil { + if err = json.Unmarshal(protocolCommon, &d.protocolCommonConfig); err != nil { + fmt.Printf("Unmarshal ProtocolCommonConfig error: %v\n", err) + return 0, err + } + } + if visitor != nil { + if err = json.Unmarshal(visitor, &d.visitorConfig); err != nil { + fmt.Printf("Unmarshal visitorConfig error: %v\n", err) + return 0, err + } + } + if protocol != nil { + if err = json.Unmarshal(protocol, &d.protocolConfig); err != nil { + fmt.Printf("Unmarshal ProtocolConfig error: %v\n", err) + return 0, err + } + } + return d.visitorConfig.Pin, nil +} + +// ReadDeviceData is an interface that reads data from a specific device, data is a type of string +func (d *GPIO) ReadDeviceData(protocolCommon, visitor, protocol []byte) (data interface{}, err error) { + // Parse raw json message to get a virtualDevice instance + pin, err := d.SetConfig(protocolCommon, visitor, protocol) + if err != nil { + return nil, err + } + pinClient := Pin(pin) + if pinClient.Read() == '0' { + return "OFF", nil + } + return "ON", nil +} + +// WriteDeviceData is an interface that write data to a specific device, data's DataType is Consistent with configmap +func (d *GPIO) WriteDeviceData(data interface{}, protocolCommon, visitor, protocol []byte) (err error) { + // Parse raw json message to get a virtualDevice instance + pin, err := d.SetConfig(protocolCommon, visitor, protocol) + if err != nil { + return err + } + status := data.(string) + pinClient := Pin(pin) + if strings.ToUpper(status) == "OFF" { + pinClient.SetOutPut() + pinClient.SetLow() + } else if strings.ToUpper(status) == "ON" { + pinClient.SetOutPut() + pinClient.SetHight() + } else { + fmt.Println("the command should be \"ON\" or \"OFF\"") + } + return nil +} + +// StopDevice is an interface to disconnect a specific device +// This function is called when mapper stops serving +func (d *GPIO) StopDevice() (err error) { + // in this func, u can get ur device-instance in the client map, and give a safety exit + fmt.Println("----------Stop gpio Device Successful----------") + return nil +} + +// GetDeviceStatus is an interface to get the device status true is OK , false is DISCONNECTED +func (d *GPIO) GetDeviceStatus(protocolCommon, visitor, protocol []byte) (status bool) { + return true +} diff --git a/mappers/gpio-atlas200/driver/gpio.go b/mappers/gpio-atlas200/driver/gpio.go new file mode 100644 index 00000000..f873521f --- /dev/null +++ b/mappers/gpio-atlas200/driver/gpio.go @@ -0,0 +1,494 @@ +/* + Atlas 200DK A1 PIN define + +------+---------+-------++------+---------+-------+ + | pin | Name |voltage|| pin | Name |voltage| + +-----+-----------+------++----+---------+-----+ + | 1 | +3.3v | 3.3V || 2 | +5.0v | 5.0V | + | 3 | SDA | 3.3V || 4 | +5.0v | 5.0V | + | 5 | SCL | 3.3V || 6 | GND | - | + | 7 | GPIO-0 | 3.3V || 8 | TXD0 | 3.3V | + | 9 | GND | - || 10 | RXD0 | 3.3V | + | 11 | GPIO-1 | 3.3V || 12 | NC | - | + | 13 | NC | 3.3V || 14 | GND | - | + | 15 | GPIO-2 | 3.3V || 16 | TXD1 | 3.3V | + | 17 | +3.3v | 3.3V || 18 | RXD1 | 3.3V | + | 19 | SPI-MOSI| 3.3V || 20 | GND | - | + | 21 | SPI-MISO| 3.3V || 22 | NC | - | + | 23 | SPI-CLK | 3.3V || 24 | SPI-CS | 3.3V | + | 25 | GND | - || 26 | NC | - | + | 27 | CAN-H | - || 28 | CAN-1 | - | + | 29 | GPIO-3 | 3.3V || 30 | GND | - | + | 31 | GPIO-4 | 3.3V || 32 | NC | - | + | 33 | GPIO-5 | 3.3V || 34 | GND | - | + | 35 | GPIO-6 | 3.3V || 36 | +1.8V | 1.8V | + | 37 | GPIO-7 | 3.3V || 38 | TXD-3559| 3.3V | + | 39 | GND | 3.3V || 40 | RXD-3559| 3.3V | + +------+---------+-------++------+---------+-------+ +gpio 0~1 are directly derived from the Ascend AI processor, +gpio 2 is not available for user +gpio 3~7 are derived from PCA6416,controlled by i2c +*/ + +package driver + +import ( + "fmt" + "io/fs" + "k8s.io/klog/v2" + "os" + "syscall" + "unsafe" +) + +// Mode type int8 +type Mode uint8 + +// Pin type int8 +type Pin uint8 + +// State type int8 +type State uint8 +type i2cMsg struct { + addr uint16 + flags uint16 + len uint16 + padding uint16 + buf uintptr +} + +type i2cCtrl struct { + msgs uintptr + msgNum uint32 +} + +const ( + ascendGpio0dir = "/sys/class/gpio/gpio504/direction" + ascendGpio1dir = "/sys/class/gpio/gpio444/direction" + ascendgpio0Val = "/sys/class/gpio/gpio504/value" + ascendgpio1Val = "/sys/class/gpio/gpio444/value" +) +const ( + i2cDeviceName = "/dev/i2c-1" + i2cRetres = 0x0701 + i2cTimeOut = 0x0702 + i2cSlave = 0x0703 + i2cRDWR = 0x0707 + i2cmRD = 0x01 + + pca6416SlaveAddr = 0x20 + pca6416GpioCfgReg = 0x07 + pca6416GpioPorarityReg = 0x05 + pca6416GpioOutReg = 0x03 + pca6416GpioInReg = 0x01 + + //GPIO MASK + gpio3Mask = 0x10 + gpio4Mask = 0x20 + gpio5Mask = 0x40 + gpio6Mask = 0x80 + gpio7Mask = 0x08 +) + +// Generic ioctl constants +const ( + iocNone = 0x0 + iocWrite = 0x1 + iocRead = 0x2 + iocNRBits = 8 + iocTypeBits = 8 + + iocSizeBits = 14 + iocDirBits = 2 + + iocNRShift = 0 + iocTypeShift = iocNRShift + iocNRBits //8 + 0 + iocSizeShift = iocTypeShift + iocTypeBits //8 + 8 + iocDirShift = iocSizeShift + iocSizeBits //16 + 14 + + iocNRMask = ((1 << iocNRBits) - 1) + iocTYPEMask = ((1 << iocTypeBits) - 1) + iocSizeMask = ((1 << iocSizeBits) - 1) + iocDirMask = ((1 << iocDirBits) - 1) +) + +const ( + // Input the pin if for input + Input Mode = iota + // Output the pin if for output + Output +) + +// State of pin, High / Low +const ( + Low uint8 = iota + High +) + +// SetInPut Set pin as inputPin +func (pin Pin) SetInPut() { + setPinMode(pin, Input) +} + +// SetOutPut Set pin as Output +func (pin Pin) SetOutPut() { + setPinMode(pin, Output) +} + +// SetHight Set pin Hight +func (pin Pin) SetHight() { + err := gpioSetValue(pin, High) + if err != nil { + klog.Errorf("gpioSetValue fail, pin %v err = %v.", pin, err) + } +} + +// SetLow Set pin as Low +func (pin Pin) SetLow() { + err := gpioSetValue(pin, Low) + if err != nil { + klog.Errorf("gpioSetValue fail, pin %v err = %v.", pin, err) + } +} + +// Write: Set pin state (high/low) +func (pin Pin) Write(val uint8) { + WritePin(pin, val) +} + +// Read pin state (high/low) +func (pin Pin) Read() uint8 { + return ReadPin(pin) +} + +// WritePin is to write value to pin +func WritePin(pin Pin, val uint8) { + err := gpioSetValue(pin, val) + if err != nil { + klog.Errorf("gpioSetValue fail, pin %v err = %v.", pin, err) + } +} + +// ReadPin is to read value of pin +func ReadPin(pin Pin) uint8 { + var val uint8 + err := gpioGetValue(pin, &val) + if err != nil { + return 0 + } + return val +} + +// setPinMode Spi mode should not be set by this directly, use SpiBegin instead. +func setPinMode(pin Pin, mode Mode) { + f := uint8(0) + const in uint8 = 0 // 000 + const out uint8 = 1 // 001 + + switch mode { + case Input: + f = in + case Output: + f = out + } + err := gpioSetDirection(pin, f) + if err != nil { + klog.Errorf("gpioSetValue fail, pin %v err = %v.", pin, err) + } +} + +// Open open a pin +func Open() (err error) { + return nil +} + +// Close close a pin +func Close() (err error) { + return nil +} +func isPca6416Pin(pin Pin) bool { + if pin >= 3 && pin <= 7 { + return true + } + return false +} + +// IOCTL send ioctl +func IOCTL(f *os.File, flag, data uintptr) error { + _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(f.Fd()), flag, uintptr(data)) + if err != 0 { + return syscall.Errno(err) + } + return nil +} + +func i2cRead(slave uint8, reg uint8, data *uint8) error { + regs := []uint8{reg, reg} + msg := []i2cMsg{ + { + addr: uint16(slave), + flags: 0, + len: uint16(1), //the length of reg addr is 1 + buf: uintptr(unsafe.Pointer(®s[0])), + }, + { + addr: uint16(slave), + flags: i2cmRD, + len: uint16(1), + buf: uintptr(unsafe.Pointer(data)), + }, + } + ssmMsg := i2cCtrl{ + msgs: uintptr(unsafe.Pointer(&msg[0])), + msgNum: uint32(len(msg)), + } + + perm := fs.FileMode(0644) //-rw-r--r-- + flag := int(os.O_RDWR | os.O_CREATE | os.O_TRUNC) + f, err := os.OpenFile(i2cDeviceName, flag, perm) + defer f.Close() + if err != nil { + return err + } + + err = IOCTL(f, i2cRDWR, uintptr(unsafe.Pointer(&ssmMsg))) + return err +} + +func i2cWrite(slave uint8, reg uint8, data uint8) error { + buf := []uint8{reg, data} + msg := []i2cMsg{ + { + addr: uint16(slave), + flags: 0, + len: uint16(len(buf)), + buf: uintptr(unsafe.Pointer(&buf[0])), + }, + } + + ssmMsg := i2cCtrl{ + msgs: uintptr(unsafe.Pointer(&msg[0])), + msgNum: uint32(1), + } + + perm := fs.FileMode(666) // -rw-rw-rw- + flag := int(os.O_RDWR | os.O_CREATE | os.O_TRUNC) + f, err := os.OpenFile(i2cDeviceName, flag, perm) + defer f.Close() + if err != nil { + return err + } + err = IOCTL(f, i2cRDWR, uintptr(unsafe.Pointer(&ssmMsg))) + return err +} + +func pca6416GpioSetDirection(pin Pin, dir uint8) error { + var err error + var data uint8 + var reg uint8 + var slave uint8 + var gpioMask = []uint8{0, 0, 0, gpio3Mask, gpio4Mask, gpio5Mask, gpio6Mask, gpio7Mask} + + if !isPca6416Pin(pin) { + err = fmt.Errorf("pin number is incorrect,must be 3 to 7") + return err + } + slave = pca6416SlaveAddr + reg = pca6416GpioCfgReg + data = 0 + err = i2cRead(slave, reg, &data) + if err != nil { + klog.Errorf("pca6416GpioSetDirection read fail, pin %v err = %v.", pin, err) + return err + } + if dir == 0 { + data |= gpioMask[pin] + } else { + data &= ^gpioMask[pin] + } + err = i2cWrite(slave, reg, data) + if err != nil { + klog.Errorf("pca6416GpioSetDirection write fail pin %v err = %v.", pin, err) + } + return err +} +func pca6416GpioSetValue(pin Pin, val uint8) error { + var err error + var data uint8 + var reg uint8 + var slave uint8 + var gpioMask = []uint8{0, 0, 0, gpio3Mask, gpio4Mask, gpio5Mask, gpio6Mask, gpio7Mask} + + if !isPca6416Pin(pin) { + err = fmt.Errorf("pin number is incorrect,must be 3 to 7") + return err + } + slave = pca6416SlaveAddr + reg = pca6416GpioOutReg + data = 0 + err = i2cRead(slave, reg, &data) + if err != nil { + klog.Errorf("pca6416GpioSetValue read fail, pin %v err = %v.", pin, err) + return err + } + if val == 0 { + data &= ^gpioMask[pin] + } else { + data |= gpioMask[pin] + } + + err = i2cWrite(slave, reg, data) + if err != nil { + klog.Errorf("pca6416GpioSetValue write fail pin %v err = %v.", pin, err) + } + return err +} +func pca6416GpioGetValue(pin Pin, val *uint8) error { + var err error + var data uint8 + var reg uint8 + var slave uint8 + var gpioMask = []uint8{0, 0, 0, gpio3Mask, gpio4Mask, gpio5Mask, gpio6Mask, gpio7Mask} + + if !isPca6416Pin(pin) { + err = fmt.Errorf("pin number is incorrect,must be 3 to 7") + return err + } + slave = pca6416SlaveAddr + reg = pca6416GpioInReg + data = 0 + err = i2cRead(slave, reg, &data) + if err != nil { + klog.Errorf("pca6416GpioSetValue read fail, pin %v err = %v.", pin, err) + return err + } + data &= gpioMask[pin] + if data > 0 { + *val = '1' + } else { + *val = '0' + } + return nil +} + +// AscendGpioSetDirection set gpio direction +func AscendGpioSetDirection(pin Pin, dir uint8) error { + var fileName string + var direction string + var err error + + if pin == 0 { + fileName = ascendGpio0dir + } else if pin == 1 { + fileName = ascendGpio1dir + } else { + err = fmt.Errorf("pin number is incorrect,must be 0 or 1") + return err + } + direction = "out" + if dir == 0 { + direction = "in" + } + err = os.WriteFile(fileName, []byte(direction), 0644) + if err != nil { + klog.Errorf("os.WriteFile fileName= %v err = %v ", fileName, err) + return err + } + + return nil +} + +// AscendGpioSetValue set gpio value +func AscendGpioSetValue(pin Pin, val uint8) error { + var fileName string + var err error + if pin == 0 { + fileName = ascendgpio0Val + } else if pin == 1 { + fileName = ascendgpio1Val + } else { + err = fmt.Errorf("pin number is incorrect,must be 0 or 1") + return err + } + klog.V(3).Infof("AscendGpioSetValue pin %v val = %v fileName = %v", pin, val, fileName) + buff := []byte{val + '0'} + err = os.WriteFile(fileName, buff, 0644) + if err != nil { + klog.Errorf("os.WriteFile fileName= %v err = %v ", fileName, err) + } + return err +} + +// AscendGpioGetValue get gpio direction +func AscendGpioGetValue(pin Pin, val *uint8) error { + var fileName string + if pin == 0 { + fileName = ascendgpio0Val + } else if pin == 1 { + fileName = ascendgpio1Val + } else { + err := fmt.Errorf("pin number is incorrect,the correct num is must be 0,1") + return err + } + readFile, err := os.ReadFile(fileName) + *val = readFile[0] + if err != nil { + klog.Errorf("AscendGpioGetValue pin %v err = %v.", pin, err) + } + klog.V(5).Infof("AscendGpioGetValue pin %v val = %v.", pin, *val) + return err +} +func isAscendPin(pin Pin) bool { + if pin == 0 || pin == 1 { + return true + } + return false +} + +// set gpio direction ,0-- in ,1--out +func gpioSetDirection(pin Pin, direction uint8) error { + var result error + if isAscendPin(pin) { + result = AscendGpioSetDirection(pin, direction) + } else { + result = pca6416GpioSetDirection(pin, direction) + } + + if nil != result { + klog.V(3).Infof("gpioSetDirection fail, pin= %v direction= %v result = %v", pin, direction, result) + } else { + klog.V(5).Infof("gpioSetDirection ok, pin= %v direction = %v", pin, direction) + } + return result +} + +func gpioSetValue(pin Pin, val uint8) error { + var result error + + if isAscendPin(pin) { + result = AscendGpioSetValue(pin, val) + } else { + result = pca6416GpioSetValue(pin, val) + } + if nil != result { + klog.V(3).Infof("gpioSetValue fail, pin= %v val= %v result = %v", pin, val, result) + } else { + klog.V(5).Infof("gpioSetValue ok, pin= %v val = %v", pin, val) + } + return result +} +func gpioGetValue(pin Pin, val *uint8) error { + var result error + + if isAscendPin(pin) { + result = AscendGpioGetValue(pin, val) + } else { + result = pca6416GpioGetValue(pin, val) + } + + if nil != result { + klog.V(3).Infof("gpioGetValue fail, pin= %v result = %v", pin, result) + } else { + klog.V(5).Infof("gpioGetValue ok, pin= %v val = %v", pin, *val) + } + return result +} diff --git a/mappers/gpio-atlas200/hack/make-rules/mapper.sh b/mappers/gpio-atlas200/hack/make-rules/mapper.sh new file mode 100644 index 00000000..74715aa0 --- /dev/null +++ b/mappers/gpio-atlas200/hack/make-rules/mapper.sh @@ -0,0 +1,190 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +CURR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" +ROOT_DIR="$(cd "${CURR_DIR}/../.." && pwd -P)" +source "${ROOT_DIR}/hack/lib/init.sh" + +mkdir -p "${CURR_DIR}/bin" +mkdir -p "${CURR_DIR}/dist" + +function mod() { + [[ "${2:-}" != "only" ]] + local mapper="${1}" + + # the mapper is sharing the vendor with root + pushd "${ROOT_DIR}" >/dev/null || exist 1 + echo "downloading dependencies for mapper ${mapper}..." + + if [[ "$(go env GO111MODULE)" == "off" ]]; then + echo "go mod has been disabled by GO111MODULE=off" + else + echo "tidying" + go mod tidy + echo "vending" + go mod vendor + fi + + echo "...done" + popd >/dev/null || return +} + +function lint() { + [[ "${2:-}" != "only" ]] && mod "$@" + local mapper="${1}" + + echo "fmt and linting mapper ${mapper}..." + + gofmt -s -w "${CURR_DIR}/" + golangci-lint run "${CURR_DIR}/..." + + echo "...done" +} + +function build() { + [[ "${2:-}" != "only" ]] && lint "$@" + local mapper="${1}" + + local flags=" -w -s " + local ext_flags=" -extldflags '-static' " + local os="${OS:-$(go env GOOS)}" + local arch="${ARCH:-$(go env GOARCH)}" + + local platform + if [[ "${ARM:-false}" == "true" ]]; then + echo "crossed packaging for linux/arm" + platform=("linux/arm") + elif [[ "${ARM64:-false}" == "true" ]]; then + echo "crossed packaging for linux/arm64" + platform=("linux/arm64") + else + local os="${OS:-$(go env GOOS)}" + local arch="${ARCH:-$(go env GOARCH)}" + platform=("${os}/${arch}") + fi + + echo "building ${platform}" + + local os_arch + IFS="/" read -r -a os_arch <<<"${platform}" + local os=${os_arch[0]} + local arch=${os_arch[1]} + GOOS=${os} GOARCH=${arch} CGO_ENABLED=0 go build \ + -ldflags "${flags} ${ext_flags}" \ + -o "${CURR_DIR}/bin/${mapper}_${os}_${arch}" \ + "${CURR_DIR}/cmd/main.go" + + cp ${CURR_DIR}/bin/${mapper}_${os}_${arch} ${CURR_DIR}/bin/${mapper} + echo "...done" +} + +function package() { + [[ "${2:-}" != "only" ]] && build "$@" + local mapper="${1}" + + echo "packaging mapper ${mapper}..." + + local image_name="${mapper}-mapper" + local tag=v1.0 + + local platform + if [[ "${ARM:-false}" == "true" ]]; then + echo "crossed packaging for linux/arm" + platform=("linux/arm") + elif [[ "${ARM64:-false}" == "true" ]]; then + echo "crossed packaging for linux/arm64" + platform=("linux/arm64") + else + local os="${OS:-$(go env GOOS)}" + local arch="${ARCH:-$(go env GOARCH)}" + platform=("${os}/${arch}") + fi + + pushd "${CURR_DIR}" >/dev/null 2>&1 + if [[ "${platform}" =~ darwin/* ]]; then + echo "package into Darwin OS image is unavailable, please use CROSS=true env to containerize multiple arch images or use OS=linux ARCH=amd64 env to containerize linux/amd64 image" + fi + + local image_tag="${image_name}:${tag}-${platform////-}" + echo "packaging ${image_tag}" + sudo docker build \ + --platform "${platform}" \ + -t "${image_tag}" . + popd >/dev/null 2>&1 + + echo "...done" +} + +function test() { + [[ "${2:-}" != "only" ]] && build "$@" + local mapper="${1}" + + echo "running unit tests for mapper ${mapper}..." + + local unit_test_targets=( + "${CURR_DIR}/config/..." + "${CURR_DIR}/configmap/..." + "${CURR_DIR}/device/..." + "${CURR_DIR}/driver/..." + ) + + local os="${OS:-$(go env GOOS)}" + local arch="${ARCH:-$(go env GOARCH)}" + if [[ "${arch}" == "arm" ]]; then + # NB(thxCode): race detector doesn't support `arm` arch, ref to: + # - https://golang.org/doc/articles/race_detector.html#Supported_Systems + GOOS=${os} GOARCH=${arch} CGO_ENABLED=1 go test \ + -cover -coverprofile "${CURR_DIR}/dist/coverage_${mapper}_${os}_${arch}.out" \ + "${unit_test_targets[@]}" + else + GOOS=${os} GOARCH=${arch} CGO_ENABLED=1 go test \ + -race \ + -cover -coverprofile "${CURR_DIR}/dist/coverage_${mapper}_${os}_${arch}.out" \ + "${unit_test_targets[@]}" + fi + + echo "...done" +} + +function clean() { + local mapper="${1}" + + echo "cleanup mapper ${mapper}..." + + rm -rf "${CURR_DIR}/bin/*" + + echo "...done" +} + +function entry() { + local mapper="${1:-}" + shift 1 + + local stages="${1:-build}" + shift $(($# > 0 ? 1 : 0)) + + IFS="," read -r -a stages <<<"${stages}" + local commands=$* + if [[ ${#stages[@]} -ne 1 ]]; then + commands="only" + fi + + for stage in "${stages[@]}"; do + echo "# make mapper ${mapper} ${stage} ${commands}" + case ${stage} in + m | mod) mod "${mapper}" "${commands}" ;; + l | lint) lint "${mapper}" "${commands}" ;; + b | build) build "${mapper}" "${commands}" ;; + p | pkg | package) package "${mapper}" "${commands}" ;; + t | test) test "${mapper}" "${commands}" ;; + c | clean) clean "${mapper}" "${commands}" ;; + *) echo "unknown action '${stage}', select from mod,lint,build,test,clean" ;; + esac + done +} + +echo $@ +entry "$@" diff --git a/mappers/gpio-atlas200/res/ca.crt b/mappers/gpio-atlas200/res/ca.crt new file mode 100644 index 00000000..af78724e --- /dev/null +++ b/mappers/gpio-atlas200/res/ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDlzCCAn+gAwIBAgIUF91PMfNuLjHukTsoNwZBGJ0iYewwDQYJKoZIhvcNAQEL +BQAwWzELMAkGA1UEBhMCQ04xDjAMBgNVBAgMBUh1YmVpMQ4wDAYDVQQHDAVXdWhh +bjEMMAoGA1UECgwDV1VUMQswCQYDVQQLDAJDUzERMA8GA1UEAwwIS3ViZWVkZ2Uw +HhcNMjIwNDIwMTUyOTAwWhcNMzIwNDE3MTUyOTAwWjBbMQswCQYDVQQGEwJDTjEO +MAwGA1UECAwFSHViZWkxDjAMBgNVBAcMBVd1aGFuMQwwCgYDVQQKDANXVVQxCzAJ +BgNVBAsMAkNTMREwDwYDVQQDDAhLdWJlZWRnZTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKgrfTmQYy/Dn8Aob8kaJ+4mbdgLJTB2kh/bw71ZRxgjZ16C +aBz024B0E0xbe8+SE2EtyAle/cBlOthPI9mAFpved0MdoCzmLBJqntHwKeWI/UtF +JAB+Wc5T612eg3V07NUniumWefOwsyzwZi+obmKMI4Lvg3D2ETmA8UlKg+ZRMZ3U +IVre26cx0Ur5ItBaLhhtlS3HGzeSDnZgEvm1sBrBXSICd16pl/bOnpNBUR7tQGpf +PXMAybR3taZXq46sFNeViDuHvGQErIl6ChdOE6bryfNNREBR4DvXDri1+yTh+44d +O4o6GOnd2zMzSIo2kYD5NtrIIF4i84Ok0l7R1cMCAwEAAaNTMFEwHQYDVR0OBBYE +FAJq+Rjj0tqDNRrW9fX1BXCUkHE6MB8GA1UdIwQYMBaAFAJq+Rjj0tqDNRrW9fX1 +BXCUkHE6MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBACl8N9+A +SVKM7MhFyjgaXKvnBImwFO4uCFhkHzRn7vph5hzQh5GfzIsPTdGkbDwCSI8VETf6 +8X1VBK0eqTLb0ID8+c4ye3Y1trl8Hi08uaJj0vPlVW9ZdFz1aGoLRHMuwvDWB7bZ +9anVvICXhNtx1x35rmYFl/I58Ly9ZArBVg5Msuhb+rfiFr2FA5VcyJZ1jp4jdXOj +bsW57AW9/tyDjCxTillC0rX8yZqTBn/4/2Joa4v/310+LpLEJNxYPqnqs0xclJpC +R7AwZjXEmxGFEmF86OM/jws8XpYVp1qyt21xenM0/mQGmxmsdQaM8Refp0+VYM6k +NWOq2Y2zIUEdv8U= +-----END CERTIFICATE----- diff --git a/mappers/gpio-atlas200/res/client.crt b/mappers/gpio-atlas200/res/client.crt new file mode 100644 index 00000000..7c44ceee --- /dev/null +++ b/mappers/gpio-atlas200/res/client.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNjCCAh4CFCArzrOzAh/rekUggX82gk68OY/WMA0GCSqGSIb3DQEBCwUAMFsx +CzAJBgNVBAYTAkNOMQ4wDAYDVQQIDAVIdWJlaTEOMAwGA1UEBwwFV3VoYW4xDDAK +BgNVBAoMA1dVVDELMAkGA1UECwwCQ1MxETAPBgNVBAMMCEt1YmVlZGdlMB4XDTIy +MDQyMDE2MTIxMFoXDTMyMDQxNzE2MTIxMFowVDELMAkGA1UEBhMCQ04xDjAMBgNV +BAgMBUh1YmVpMQ4wDAYDVQQHDAVXdWhhbjERMA8GA1UECgwIa3ViZWVkZ2UxEjAQ +BgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AMHqnxg3osjKfNBqsooOnMdA/Jf5o0uf33oxvd7eXIYNNnUyvDIZ9kgt0IQHyamn +2BNDfMyDfXz6wHDuFV97+JtyLS1TLRMP4gGWGR/JC+iGNP0TGEtaEcwv7n1nRSkg +6j3FWErAvUhWU0Vlse7MB0GXevqezfDpSLeJLJvZ552C7SBTfLzBbNPhd2joJ/vJ +fKGz5f/OieGvhi7/0WmPzHH4RqT9q/va56FIO4MuEjhpRmg9OAsB/EAaOi9QFMD2 +rQkbRfA22hXA8PGqMq1PAnRwBUaWbwnwPNGm5rVeBMQfI4D8/JA+QYnXHrNMbSjC +cFwZmMIwC/TtwZ/GjwHSJmsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAPjXQx3+p +wQVJ/GxE0jNAzdwm9MolvYgTzifpA693kTra5NSdocpQKFpqWJJ8NczaJyBn6JCg +X5Zx9xwD2wrNScelcQkOENg2ZjtAsiHESBtmkf+vBvj9QlBDrGtTDE5KQjg2ZgcU +EcFSjix685GxuxONRFXhvdRL+D1oAisoqvMjZTXbmbTV7h0Fke84GERxDmBvHKnj +SFVv+xoB3CSmD/LSn9baMed/akGpQG0IZ29nWlVLxHpaiUbhzrlEuNyVU/2qupZr +ffhKVhxD+z9j/1N/hkmbEOtZXwuwyOF7seUZktyyC+55t9XABfRBh85HYm+U/wqT +cWfh+yFb+3RsVA== +-----END CERTIFICATE----- diff --git a/mappers/gpio-atlas200/res/client.key b/mappers/gpio-atlas200/res/client.key new file mode 100644 index 00000000..e484df85 --- /dev/null +++ b/mappers/gpio-atlas200/res/client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAweqfGDeiyMp80Gqyig6cx0D8l/mjS5/fejG93t5chg02dTK8 +Mhn2SC3QhAfJqafYE0N8zIN9fPrAcO4VX3v4m3ItLVMtEw/iAZYZH8kL6IY0/RMY +S1oRzC/ufWdFKSDqPcVYSsC9SFZTRWWx7swHQZd6+p7N8OlIt4ksm9nnnYLtIFN8 +vMFs0+F3aOgn+8l8obPl/86J4a+GLv/RaY/McfhGpP2r+9rnoUg7gy4SOGlGaD04 +CwH8QBo6L1AUwPatCRtF8DbaFcDw8aoyrU8CdHAFRpZvCfA80abmtV4ExB8jgPz8 +kD5Bidces0xtKMJwXBmYwjAL9O3Bn8aPAdImawIDAQABAoIBAFDEB79ubL50l8e2 +qOYXb/UNfCdQMlMtI0chsJNCygaLOkNV/kxfw9QMQOy80aF35ucfFLuZiIqlZcGj +aAN8/u6/f1GBcySdWOSQP6addfhC7Y76hQPdX8xLqmlQud2HeAiCSWPZIv0d91DQ +KmvrTppjHTWFLwFIKKFI4OuIto9DXxpEXExwYrHFJhbKtLuAKZiG2BJ0P4qP30EE +XHpgOOJisZpISoN6/2PpgoOb96Y1YAtUdLe1isLHuPbvDvePhiYNQN0WkXCfbabS +Jf2AMr9QpnARB6paJPyKgMp0vYjayuk7oDmHw7O+RjsX8pMH+ZIq3OgJ2wajuE8Q +FcXE2AECgYEA4/rj1JsOMLYAapNkQpTqdKb2XgaH+dLfvpvnqB6rZX4pd5kaNyOh +8Bs8x0phj01c6VJb6HlK2nEZCpjp3nnO8lUm/2OAyb2pWAKhT3SfOsVjJIYN13M7 +mICLW+LjVAz3NpEncYjzVlytXJo8W6Sux9v7um2Tz2tKtESwfLnEXGECgYEA2b/2 +zEnMAKxceYO5zyKMc31v8fpcTXFn2NKvcaH1BzDF6vxW9OJf9IhcubndD/Pt/j3n +UA4q9ENG2l3m6C91yAGAqmRGlYdaPVbgjT27CDar4tifeoVIJ9sEKHy+cRz3uK2/ +PuaBRA2h3JIG78zBm6Z9dum0hGk8bARGC3lS1ksCgYBXa/7vqSHQ5gnU1H5O1eHu +J5QzzBdaYlWwNwKnQlOBUNa/6PLXkA9qDlfJKCmvFQB67D0YMWLVzybGHIsZ5+XG +oYaZymM5eUQ13pRS7qqck9KHz+wA4UxKF4jZDHEV6v7latYQQG7ngBRufSqGDemD +9ERcYeabVE5KQEjZGzdEIQKBgQDFOEbyFMz+tx4yuQor/6CyYaRoyFedlN931Ksv +An+JebVo9hBUUEyUkIVbemosrsSaB7tgGNTy05Ry56XiGkpVUncU3SnI+QTUlcFg +a87gy5O3LHiVYe5OmuITQZjDnncH/+Y9tEzUNHyr6F78Bro8nfj5IQds/lvJgb1n +WwWaLQKBgDCgRxPLWUv08gaKHoDR383IbbDW+noFYRJa5y03ZmW4qPicLZ/SNcAT +oOAS0uyWJWBB00ZGIGd6kcOZ6ipvaI5472LbAQL//UATQ7iHoIFc/YD659NOea9o +eolNFDKalPzfmg5xCHxKDtoO79EXlFvovPitePv+7IeVncCX7oHY +-----END RSA PRIVATE KEY----- diff --git a/mappers/gpio-atlas200/res/config.yaml b/mappers/gpio-atlas200/res/config.yaml new file mode 100644 index 00000000..e2145a3f --- /dev/null +++ b/mappers/gpio-atlas200/res/config.yaml @@ -0,0 +1,14 @@ +mqtt: + server: mqtt://127.0.0.1:1884 + servername: 127.0.0.1 + username: "" + password: "" + clientId: "" + certification: "" + privatekey: + caCert: +http: + certification: "" + privatekey: "" + caCert: "" +configmap: /opt/kubeedge/deviceProfile.json diff --git a/mappers/gpio-atlas200/res/server.crt b/mappers/gpio-atlas200/res/server.crt new file mode 100644 index 00000000..c4587c40 --- /dev/null +++ b/mappers/gpio-atlas200/res/server.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIUICvOs7MCH+t6RSCBfzaCTrw5j9cwDQYJKoZIhvcNAQEL +BQAwWzELMAkGA1UEBhMCQ04xDjAMBgNVBAgMBUh1YmVpMQ4wDAYDVQQHDAVXdWhh +bjEMMAoGA1UECgwDV1VUMQswCQYDVQQLDAJDUzERMA8GA1UEAwwIS3ViZWVkZ2Uw +HhcNMjIwNDIwMTYzNTM4WhcNMzIwNDE3MTYzNTM4WjBNMQswCQYDVQQGEwJDTjEO +MAwGA1UECAwFSHViZWkxDjAMBgNVBAcMBVd1aGFuMQswCQYDVQQKDAJDUzERMA8G +A1UEAwwIS3ViZWVkZ2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4 +U/0DhAQMWLsOuWy3QpyYYCK8PxGuU9aYll7Q4oZUxNC1cZ6HnJlW0fXVJ4AOPdU7 +4XbCmDQDq4fnyKb1M0jMKCSJXnSsxVjUodTsZ8zw6zzoqed+O34oA2T0UKpZkM9b +fOIsgQdlyBw/TS5HBmwNKwgE3wjFrTQQw+WSmeCUyVcPyUxpjD7h44981mZkygua +GrdL/W5h9v4p3oAAGyH5BHwaaJ1O4FUXRyqssGlGE3uwFniXdo7Md8LAeqvsQHSe +0uZCeLZ+5Pwm+ou3v6fLzTwR3MrevOM3VUukCoYq/G8twQsejv9RakIG6HGsxNrq +/bcnOyg7XdO6jZ9VzWw5AgMBAAGjHjAcMBoGA1UdEQQTMBGHBH8AAAGCCWxvY2Fs +aG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAdEf8xOzRl3c2Aohb6sB8Ecjr2E9U4iXz +rAVsOQe60675REXDDq34bqQdZ3CFzf9CfgoV1xVbkfeVE2FaiSD0qq5PDT6VHT23 +eXeHcQqU7JuTggld0P3/ou/lC28psvatkEM3wSjkUYA9kAK1sIICkcoD7Htop4U+ +glu+LuEJZrVVBmeyZDFLkUB1bdjw1uTSehdGUulbCtHrdRn4TqTCkWypAAvV4gFX +rrGjZMLHrM97etevraRaPwSVcYYhyR7eGlgk+Nu0ptX4epLFqtLF3tw7Qkb/fSJf +Xsc1kkuaAVUw9N31wsYg+rOwUpRk2hGlkMQ1OCMBHiIHP+U03G9xgA== +-----END CERTIFICATE----- diff --git a/mappers/gpio-atlas200/res/server.key b/mappers/gpio-atlas200/res/server.key new file mode 100644 index 00000000..ff2ed566 --- /dev/null +++ b/mappers/gpio-atlas200/res/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAuFP9A4QEDFi7Drlst0KcmGAivD8RrlPWmJZe0OKGVMTQtXGe +h5yZVtH11SeADj3VO+F2wpg0A6uH58im9TNIzCgkiV50rMVY1KHU7GfM8Os86Knn +fjt+KANk9FCqWZDPW3ziLIEHZcgcP00uRwZsDSsIBN8Ixa00EMPlkpnglMlXD8lM +aYw+4eOPfNZmZMoLmhq3S/1uYfb+Kd6AABsh+QR8GmidTuBVF0cqrLBpRhN7sBZ4 +l3aOzHfCwHqr7EB0ntLmQni2fuT8JvqLt7+ny808EdzK3rzjN1VLpAqGKvxvLcEL +Ho7/UWpCBuhxrMTa6v23JzsoO13Tuo2fVc1sOQIDAQABAoIBAQCavs/bYrovT1KC +swJk+4QRnCutE9mZG4M+CIdDH9kcUzrQCLnJKZvFunCCaS3lRt277rVP+o04Q4nN ++bLIiSxlUJITzPtwjCDeKZpieWYhH6u7u9+/JtzrZKYdQZcxqBOcv8P1DsGSHiQw +tG/UarzNdUG/LSrlIVpjdMJHh+11mgE3EtqmUkq/3qHg1iyaucB7eLwbt4+ZrHof +kCWW7XrjwWaFH5lLJYwmC99iGcNusF9R3gC3y+iNtdXCo97FFkb821rJFGJGaUK9 +S11GnooN/8dQbAa69bJfqABCxmuXgMHRegRdm7bF37lI0BqOEPaAPHaTbtC/uNBV +Ss0pcBENAoGBANzVZoOMv3TVXl9ZxVC2gx5Nmr9nI0uegHbyDWENwXjIi9pUaR3o +y+i/Figd35RhgbyqOHOAXL7lwuAxqXVoTqgYnc4I8AqVx8I6sTCWUf3YdkB9FyLU +boPBT4l9eUlV96ZAUny9cDNC/SApF4ymgopbpdN6/JblXK6NR0uwyIwDAoGBANWu +Y1D7vzYutCDHtL/up0ie+hKb6NZtJC5y9+qXauQ+SzMJJN9tYYfEIoX9UoU941Xd +ixxxu4TJM1OOkoWiWLsaX7xee2i0W04Ydgfk7VUr6AScjz1VoW0hNP2ihekheWGg +YnbDRz96oyqHGh7wU8w77iXF4CikcOr31ci07lgTAoGAEwEqeVe7gkp6fKo1GOUc +E5eKIb62guN5GsNp81hDtilMH9Xz1eca5UTMm1c2zoY1rA7aHNaHJMaRJsofU0NO +wZicvAZ44fBR6J00coH9PGNMifA59X1ipWQVfDeYIH+NeHlAoAuNhFvXfNUMecY6 +pb2NX83Nvw6uEzeFUzY7jBECgYAQJVUr0VnpZi4GLBDkT8wkGJ8cuNsnGKgbOmSx +PS++f1Z/TLmUiFdOQuu45CNQHhUHb+4LAC0DI5DVR3ia0GGUAbIqMZlxl+8uP3rr +rcihHugxMQNBxy6jaFbws08bBoR9c/j8sFS53zJlDEBVBiPO0thz0jfV2lcN6hwl +RkacMQKBgGZIJVYcLQHfn6SpurWSPoUBHjfsVcA9vWfBtmCzuMHds8oi6DDu/gHe +JVTo/+Ocolqg3FCT9NxSo+5vF6PXUnLk4VQ2BogaGIIf7ZTUJodPvVq5cr5o2S90 +h9iXKUkhwCQT879hKQIJ666GEQUUrhG8l7qWwx/mjC2CH1GfrZbm +-----END RSA PRIVATE KEY-----