// // FrequencyOperation.swift // Logger4 // // Created by Kilian Hofmann on 15.06.17. // Copyright © 2017 Kilian Hofmann. All rights reserved. // import Cocoa class FrequencyOperation: Operation { // DOCSIS 3.0 Upstream Power Limits as per Specification March 5. 2015 let upstreamOne = ["qpsk": "62.18", "8qam": "58.21", "16qam": "58.21", "32qam": "57", "64qam": "57", "128qam": "-"] let upstreamTwo = ["qpsk": "59.18", "8qam": "55.21", "16qam": "55.21", "32qam": "54", "64qam": "54", "128qam": "-"] let upstreamThreeOrFour = ["qpsk": "56.18", "8qam": "52.21", "16qam": "52.21", "32qam": "51", "64qam": "51", "128qam": "-"] let modulationAdjust: NSDictionary = ["qpsk": "-1.18", "8qam": "-0.21", "16qam": "-0.21", "32qam" : "0", "64qam": "0", "128qam": "0.05"] // XML Parser let parser: XMLDictionaryParser = XMLDictionaryParser() // Data handling var downstream: Data? var upstream: Data? var upstreamBool: Bool = false var downstreamBool: Bool = false var dir: NSString = "" override init() { } override func main() { // Get date for folder structure let time : Date = Date() let start: Array = (NSApp.delegate as! AppDelegate).justDate.string(from: time).components(separatedBy: ".") // File manager let fileManager: FileManager = FileManager.default // Make all relevant directories if not present pthread_mutex_lock(&((NSApp.delegate as! AppDelegate).lock)) dir = NSString(format: "~/KDLog/%@.docsisplist2/%@/%@/", start[2], start[1], start[0]) do { try fileManager.createDirectory(atPath: dir.expandingTildeInPath, withIntermediateDirectories: true, attributes: nil) } catch let error as NSError{ NSLog("ERROR ON SUBDIRECTORY CREATION: \(error.localizedDescription)") } pthread_mutex_unlock(&((NSApp.delegate as! AppDelegate).lock)) // URL Requests let requestDownstream: URLRequest = URLRequest.init(url: URL.init(string: UserDefaults.standard.string(forKey: "downstream")!)!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 4) let requestUpstream: URLRequest = URLRequest.init(url: URL.init(string: UserDefaults.standard.string(forKey: "upstream")!)!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 4) // Tasks let taskDownstream: URLSessionDataTask = (NSApp.delegate as! AppDelegate).urlSession.dataTask(with: requestDownstream){data, response, error in pthread_mutex_lock(&(NSApp.delegate as! AppDelegate).lock) self.downstream = data self.downstreamBool = true self.handleData(date: time) pthread_mutex_unlock(&(NSApp.delegate as! AppDelegate).lock) } let taskUpstream: URLSessionDataTask = (NSApp.delegate as! AppDelegate).urlSession.dataTask(with: requestUpstream){data, response, error in pthread_mutex_lock(&(NSApp.delegate as! AppDelegate).lock) self.upstream = data self.upstreamBool = true self.handleData(date: time) pthread_mutex_unlock(&(NSApp.delegate as! AppDelegate).lock) } // Start taskUpstream.resume() taskDownstream.resume() } func handleData(date: Date) { // Both returned successfully if upstream != nil && downstream != nil { // Parse data upstreamBool = false downstreamBool = false let dictionaryUpstream: Dictionary? = parser.dictionary(with: upstream) let dictionaryDownstream: Dictionary? = parser.dictionary(with: downstream) upstream = nil downstream = nil // Tracking padding adding var filesModified: [String] = [] // Upstream is valid if dictionaryUpstream != nil{ var entry: String = "" var file: NSString = "" // Grab channels let channels: AnyObject = (dictionaryUpstream!["upstream_channel"]) as AnyObject // We have multiple channels if channels is [Dictionary] { // Simplify let channels: [Dictionary] = (channels as! [Dictionary]) // Step through channels for index in 0.. = channels[index] // We do not have an error if channel["upstream_modulation"] != nil && (channel["frequency"] as! String) != "status_error" { // Grab power rating in dBmV let powerInt: Double? = Double(channel["power_level"] as! String) // We have valid power rating if powerInt != nil { // Grab modulation data let modulation: NSObject = ((channel["upstream_modulation"]!)["modulation"])! as! NSObject // Grab power adjustment see DOCSIS 3.0 Specification for more Information) var adjust: String = "" if modulation.isKind(of: NSArray.self) { adjust = modulationAdjust[(((modulation as! NSArray)[0] as! NSDictionary)["mod_type"]!) as! String]! as! String } else{ adjust = modulationAdjust[((modulation as! NSDictionary)["mod_type"]!) as! String]! as! String } let adjustInt: Double = Double(adjust)! // Add timestamp and power to file entry entry = "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));\(String(powerInt! + adjustInt));" // Add threshold to file entry switch channels.count { case 2: entry += "\(upstreamTwo[modulationAdjust.allKeys(for: adjust)[0] as! String]!)" case 3: entry += "\(upstreamThreeOrFour[modulationAdjust.allKeys(for: adjust)[0] as! String]!)" case 4: entry += "\(upstreamThreeOrFour[modulationAdjust.allKeys(for: adjust)[0] as! String]!)" default: entry += "NaN" } // Add ranging status entry += ";\(channel["ranging_status"] as! String)" // Add file name to path file = dir.appending("Upstream \(channel["frequency"]!).hex") as NSString // Track modification filesModified.append("Upstream \(channel["frequency"]!).hex") // Write to file FileOperations.logUpstream(data: entry, toFrequencyLog: file.expandingTildeInPath) } } } } // We have a single channel else if channels is Dictionary { // Grab channel let channel: Dictionary = channels as! Dictionary // We do not have an error if channel["upstream_modulation"] != nil && channel["frequency"] as! String != "status_error" { // Grab power rating in dBmV let powerInt: Double? = Double(channel["power_level"] as! String) // We have valid power rating if powerInt != nil { // Grab modulation data let modulation: NSObject = ((channel["upstream_modulation"]!)["modulation"])! as! NSObject // Grab power adjustment see DOCSIS 3.0 Specification for more Information) var adjust: String = "" if modulation.isKind(of: NSArray.self) { adjust = modulationAdjust[(((modulation as! NSArray)[0] as! NSDictionary)["mod_type"]!) as! String]! as! String } else{ adjust = modulationAdjust[((modulation as! NSDictionary)["mod_type"]!) as! String]! as! String } let adjustInt: Double = Double(adjust)! // Add data to entry entry = "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));\(String(powerInt! + adjustInt));\(upstreamOne[modulationAdjust.allKeys(for: adjust)[0] as! String]!);\(channel["ranging_status"] as! String)" // Add file name to path file = dir.appending("Upstream \(channel["frequency"]!).hex") as NSString // Track modifiction filesModified.append("Upstream \(channel["frequency"]!).hex") // Write to file FileOperations.logUpstream(data: entry, toFrequencyLog: file.expandingTildeInPath) } } } } // Downstream is valid if dictionaryDownstream != nil { var entry: String = "" var file: NSString = "" // Grab channels let channels: AnyObject = (dictionaryDownstream!["downstream_channel"]) as AnyObject // We have multiple channels if channels is [Dictionary] { // Simplify let channels: [Dictionary] = channels as! [Dictionary] // Step through channels for index in 0.. = channels[index] // We do not have an error if channel["frequency"] as! String != "status_error" { // Add data to entry entry = "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));\(channel["power_level"]!);\(channel["snr"]!)" // Add file name to path file = dir.appending("Downstream \(channel["frequency"]!).hex") as NSString // Tracking modification filesModified.append("Downstream \(channel["frequency"]!).hex") // Write to file FileOperations.logDownstream(data: entry, toFrequencyLog: file.expandingTildeInPath) } } } // We have a single channel else if channels is Dictionary { // Grab channel let channel: Dictionary = channels as! Dictionary // We do not have an error if channel["frequency"] as! String != "status_error" { // Add data to entry entry = "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));\(channel["power_level"]!);\(channel["snr"]!)\n" // Add file name to path file = dir.appending("Downstream \(channel["frequency"]!).hex") as NSString // Tracking modification filesModified.append("Downstream \(channel["frequency"]!).hex") // Write to file FileOperations.logDownstream(data: entry, toFrequencyLog: file.expandingTildeInPath) } } } // Update if not modified let fileManager = FileManager.default // Get all filenames in directory let enumerator:FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: dir.expandingTildeInPath)! // Step through files for element in enumerator { // Check if modified if !filesModified.contains(element as! String) && (element as! String).contains(".hex") { logDummie(dir: dir, element: element as! String, date: date) } } } // Update if both nil (no connection to modem possible) else if (upstreamBool && downstreamBool) { upstreamBool = false downstreamBool = false let fileManager = FileManager.default // Get all filenames in directory let enumerator:FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: dir.expandingTildeInPath)! // Step through files for element in enumerator { logDummie(dir: dir, element: element as! String, date: date) } } } func logDummie(dir: NSString, element: String, date: Date) { if element.contains("Upstream") { FileOperations.logUpstream(data: "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));-;-;-", toFrequencyLog: (dir.appending(element) as NSString).expandingTildeInPath) } else if element.contains("Downstream") { FileOperations.logDownstream(data: "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));-;-", toFrequencyLog: (dir.appending(element) as NSString).expandingTildeInPath) } } }