[swift]モールス信号をiPhone/iPadのフラッシュで行ってみる

# はじめに
ふとモールス信号の仕組みってどうなっているんだ？と思ったのでモールス信号を発光するアプリを作ってみた
途中からめんどくさくなってかなりソースコードが汚くなっていますがご了承ください

# ソースコード
## EnumEnumerable.swift

``` swift
import Foundation

public protocol EnumEnumerable {
    associatedtype Case = Self
    static var dict: [String:String] {get}
}

public extension EnumEnumerable where Case: Hashable {
    private static var iterator: AnyIterator<Case> {
        var n = 0
        return AnyIterator {
            defer { n += 1 }
            
            let next = withUnsafePointer(to: &n) {
                UnsafeRawPointer($0).assumingMemoryBound(to: Case.self).pointee
            }
            return next.hashValue == n ? next : nil
        }
    }
    
    public static func enumerate() -> EnumeratedSequence<AnySequence<Case>> {
        return AnySequence(self.iterator).enumerated()
    }
    
    public static var cases: [Case] {
        return Array(self.iterator)
    }
    
    
    public static var count: Int {
        return self.cases.count
    }
}
```
## Morse.swift
```swift

protocol Morse {
    static func patern(original: String) -> String
}
```

## WesternMorse.swift
```swift
enum WesternMorse: String, Morse, EnumEnumerable {
    case A = "・－"
    case B = "－・・・"
    case C = "－・－・"
    case D = "－・・"
    case E = "・"
    case F = "・・－・"
    case G = "－－・"
    case H = "・・・・"
    case I = "・・"
    case J = "・－－－"
    case K = "－・－"
    case L = "・－・・"
    case M = "－－"
    case N = "－・"
    case O = "－－－"
    case P = "・－－・"
    case Q = "－－・－"
    case R = "・－・"
    case S = "・・・"
    case T = "－"
    case U = "・・－"
    case V = "・・・－"
    case W = "・－－"
    case X = "－・・－"
    case Y = "－・－－"
    case Z = "－－・・"
    //数字
    case one = "・－－－－"
    case two = "・・－－－"
    case three = "・・・－－"
    case four = "・・・・－"
    case five = "・・・・・"
    case six = "－・・・・"
    case seven = "－－・・・"
    case eight = "－－－・・"
    case nine = "－－－－・"
    case zero = "－－－－－"
    //記号
    case question = "・・－－・・"
    case exclamation = "－・－・－－"
    case period = "・－・－・－"
    case comma = "－－・・－－"
    case hyphen = "－・・・・－"
    case blank = "____"
    case delimiter = "___"
    
    
    public static var dict: [String:String] {
        var value = [String: String]()
        for var k in self.cases{
            value["\(k)"] = "\(k.rawValue)"
        }
        return value
    }
    
    static func patern(original: String) -> String {
        var returnValue = ""
        for char in original.characters {
            let charStr = transformation((String(char).uppercased()))
            returnValue += self.dict["\(charStr)"]! + self.dict["delimiter"]!
        }
        return returnValue
    }
    
    private static func transformation(_ char: String) -> String {
        let numArray = ["zero","one","two","three","four","five","six","seven","eight","nine"]
        if char.isNumber() {
            return numArray[Int(char)!]
        }
        switch char {
        case "!":
            return "exclamation"
        case "?":
            return "question"
        case ",":
            return "comma"
        case ".":
            return "period"
        case "-":
            return "hyphen"
        case " ","　":
            return "blank"
        default:
            return char
        }
    }
}
```

##MorseSignalDevice.swift
```swift
protocol MorseSignalDevice {
    func device() -> AVCaptureDevice
}

enum morseSignalDevice : MorseSignalDevice{
    case torch
    func device() -> AVCaptureDevice {
        switch self {
        case .torch:
            let avDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
            guard let device = avDevice else {
                return AVCaptureDevice()
            }
            return device            
        }
    }
}
```

## MorseSignal.swift
```
import Foundation
import AVFoundation


protocol MorseSignal {
    static func outSignal(signal: String, device: AVCaptureDevice)
}

public enum torchHandler: MorseSignal{
    public static func outSignal(signal: String, device: AVCaptureDevice){
        do {
            try device.lockForConfiguration()
        } catch {
            return
        }
        let sleepTime: useconds_t = 100000
        for char in signal.characters {
            switch String(char) {
            case "・":
                device.torchMode = .on
                usleep(sleepTime)
                device.torchMode = .off
            case "－":
                device.torchMode = .on
                usleep(sleepTime*3)
                device.torchMode = .off
            case "_":
                device.torchMode = .off
                usleep(sleepTime)
            default:
                usleep(0)
            }
        }
        device.unlockForConfiguration()
        
    }

}
```

## ViewController.swift
使うときは以下のようにするとできます

```swift

@IBAction func pushMorseSignal(_ sender: Any) {
        let signal = WesternMorse.patern(original: textField.text!)
        let device = morseSignalDevice.torch.device()
        if device.hasTorch {
            
            torchHandler.outSignal(signal: signal, device: device)
        }
}
```
## String+.swift
```swift
import Foundation

extension String {
    func isNumber() -> Bool {
        let predicate = NSPredicate(format: "SELF MATCHES '\\\\d+'")
        return predicate.evaluate(with: self)
    }

}
```

# 作ってみて
和文モールスもcaseだけは書いたんですが力尽きました
ただひたすらcase文とモールス信号パターンを打つのがめんどくさかったです

# 参考
[iPhoneのLEDライトをLピカさせよう！
](http://qiita.com/nnsnodnb/items/36540f1c199552f1ea25)
[Swift3.0版、Enumのcaseを配列で返すProtocol Extension
](http://qiita.com/su_k/items/c1c6a91324cf12151256)